/[ascend]/trunk/models/johnpye/datareader/dr.c
ViewVC logotype

Contents of /trunk/models/johnpye/datareader/dr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1775 - (show annotations) (download) (as text)
Wed May 21 09:51:59 2008 UTC (14 years, 4 months ago) by jpye
File MIME type: text/x-csrc
File size: 9972 byte(s)
Silenced som runtime debug output for datareader and solver.
Added first shot at canvas gui code using Gaphas.
1 /* ASCEND modelling environment
2 Copyright (C) 2006 Carnegie Mellon University
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program 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 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18 */
19
20 #include <errno.h>
21
22 #include "dr.h"
23 #include "tmy.h"
24 #include "acdb.h"
25
26 #include <utilities/config.h>
27 #include <general/ospath.h>
28 #include <utilities/ascMalloc.h>
29 #include <utilities/error.h>
30 #include <utilities/ascPanic.h>
31 #include <utilities/ascEnvVar.h>
32
33 #define DR_DEBUG 0
34
35 /*------------------------------------------------------------------------------
36 FORWARD DECLARATIONS
37 */
38
39 /*
40 declare the possible formats that we will accept ('format' child in the
41 DATA instance of the external relation
42 */
43
44 #define FMTS(D,X) D(TMY2) X D(ACDB) X D(CSV) X D(TDV)
45
46 #define ENUM(F_) DATAREADER_FORMAT_##F_
47 #define COMMA ,
48 typedef enum{
49 FMTS(ENUM,COMMA),
50 DATAREADER_INVALID_FORMAT
51 } DataReaderFormat;
52 #undef ENUM
53 #undef COMMA
54
55
56 /*------------------------------------------------------------------------------
57 API FUNCTIONS
58 */
59
60 /**
61 Create a data reader object, with the filename specified. The filename
62 will be searched for in a specified path, eg ASCENDLIBRARY.
63 */
64 DataReader *datareader_new(const char *fn){
65 DataReader *d;
66
67 d = ASC_NEW(DataReader);
68 d->fn = fn;
69 d->fp = NULL;
70 d->f = NULL;
71 d->noutputs = 0;
72
73 d->datafn=NULL;
74 d->headerfn=NULL;
75 d->eoffn=NULL;
76
77 CONSOLE_DEBUG("Datareader created...");
78 return d;
79 }
80
81 /**
82 Set data file format
83 @return 0 on success
84 */
85 int datareader_set_format(DataReader *d, const char *format){
86
87 #define STR(N) #N
88 #define COMMA ,
89 const char *fmts[]={ FMTS(STR,COMMA) };
90 #undef STR
91 #undef COMMA
92
93 int i;
94
95 CONSOLE_DEBUG("FORMAT '%s'",format);
96
97 DataReaderFormat found = DATAREADER_INVALID_FORMAT;
98 for(i=0; i < DATAREADER_INVALID_FORMAT; ++i){
99 if(strcmp(format,fmts[i])==0){
100 found = (DataReaderFormat)i;
101 break;
102 }
103 }
104
105 CONSOLE_DEBUG("FOUND DATA FORMAT %d",found);
106
107 switch(found){
108 case DATAREADER_FORMAT_TMY2:
109 d->headerfn=&datareader_tmy2_header;
110 d->datafn=&datareader_tmy2_data;
111 d->eoffn=&datareader_tmy2_eof;
112 d->indepfn=&datareader_tmy2_time;
113 d->valfn=&datareader_tmy2_vals;
114 break;
115 case DATAREADER_FORMAT_ACDB:
116 d->headerfn=&datareader_acdb_header;
117 d->datafn=&datareader_acdb_data;
118 d->eoffn=&datareader_acdb_eof;
119 d->indepfn=&datareader_acdb_time;
120 d->valfn=&datareader_acdb_vals;
121 break;
122 case DATAREADER_FORMAT_TDV:
123 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Tab delimited values (TDV) format not yet implemenented.");
124 return 1;
125 case DATAREADER_FORMAT_CSV:
126 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Comma-separated values (TDV) format not yet implemenented.");
127 return 1;
128 default:
129 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Unknown file format '%s' specified",format);
130 return 1;
131 }
132
133 return 0;
134 }
135
136 typedef struct DataFileSearchData_struct{
137 struct FilePath *fp; /**< the relative path we're searching for */
138 ospath_stat_t buf; /**< saves memory allocation in the 'test' fn */
139 int error; /**< error code (in case stat or fopen failed) */
140 struct FilePath *fp_found; /**< the full path we found */
141 } DataFileSearchData;
142
143 FilePathTestFn datareader_searchpath_test;
144
145 /**
146 @return 1 on success
147 */
148 int datareader_searchpath_test(struct FilePath *path,void *searchdata){
149 struct FilePath *fp1;
150 DataFileSearchData *sd;
151
152 sd = (DataFileSearchData *)searchdata;
153 assert(sd!=NULL);
154 assert(sd->fp!=NULL);
155
156 fp1 = ospath_concat(path,sd->fp);
157 if(fp1==NULL){
158 CONSOLE_DEBUG("Couldn't concatenate path");
159 return 0;
160 }
161
162 if(ospath_stat(fp1,&sd->buf)){
163 sd->error = errno;
164 ospath_free(fp1);
165 return 0;
166 }
167
168 sd->fp_found = fp1;
169 return 1;
170 };
171
172
173 /**
174 Initialise the datareader: open the file, check the number of columns, etc.
175 @return 0 on success
176
177 @TODO search for the file in the ASCENDLIBRARY if not found immediately
178 */
179 int datareader_init(DataReader *d){
180 ospath_stat_t s;
181 char *tmp;
182 struct FilePath **sp1, *fp2;
183 DataFileSearchData sd;
184
185 d->fp = ospath_new(d->fn);
186 if(d->fp==NULL){
187 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Invalid filepath");
188 return 1;
189 }
190
191 if(ospath_stat(d->fp,&s)){
192 if(errno==ENOENT){
193 /* file doesn't exist: check the search path instead */
194 tmp = Asc_GetEnv(ASC_ENV_LIBRARY);
195 if(tmp==NULL){
196 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"No paths to search (is env var '%s' set?)",ASC_ENV_LIBRARY);
197 return 1;
198 }
199
200 sp1 = ospath_searchpath_new(tmp);
201 if(sp1==NULL){
202 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"Unable to process %s value '%s'",ASC_ENV_LIBRARY,tmp);
203 /* memory error */
204 ascfree(tmp);
205 return -3;
206 }
207 ascfree(tmp);
208
209 sd.fp = d->fp;
210
211 fp2 = ospath_searchpath_iterate(sp1, &datareader_searchpath_test, &sd);
212
213 if(fp2==NULL){
214 ERROR_REPORTER_HERE(ASC_USER_ERROR,"File '%s' not found in search path (error %d)",d->fn,sd.error);
215 ospath_searchpath_free(sp1);
216 return -1;
217 }
218
219 ospath_searchpath_free(sp1);
220
221 /* replace our relative path with an absolute one */
222 ospath_free(d->fp);
223 d->fp = sd.fp_found;
224
225 }else{
226 ERROR_REPORTER_HERE(ASC_USER_ERROR,"The file '%s' cannot be accessed.\n"
227 "Check the file privileges, or try specifying an absolute path.",d->fn
228 );
229 return 1;
230 }
231 }
232
233 CONSOLE_DEBUG("About to open the data file");
234
235 d->f = ospath_fopen(d->fp,"r");
236 if(d->f == NULL){
237 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Unable to open file '%s' for reading.",d->fn);
238 return 1;
239 }
240
241 CONSOLE_DEBUG("Data file open ok");
242
243 asc_assert(d->headerfn);
244 asc_assert(d->eoffn);
245 asc_assert(d->datafn);
246
247 if((*d->headerfn)(d)){
248 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Error processing file header in '%s'",d->fn);
249 fclose(d->f);
250 return 1;
251 }
252
253 while(! (*d->eoffn)(d)){
254 if((*d->datafn)(d)){
255 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Error reading file data in '%s'",d->fn);
256 fclose(d->f);
257 return 1;
258 }
259 }
260 fclose(d->f);
261
262 d->i = 0; /* set current position to zero */
263
264 return 0;
265 }
266
267 /**
268 Shut down the data reader and deallocate any memory owned by it, then
269 free the memory at d.
270 */
271 int datareader_delete(DataReader *d){
272 if(d->fp){
273 ospath_free(d->fp);
274 d->fp = NULL;
275 }
276 if(d->f){
277 fclose(d->f);
278 d->f = NULL;
279 }
280 ASC_FREE(d);
281 return 0;
282 }
283
284 /**
285 Return the number of inputs (independent variables) supplied in the
286 DataReader's current file. Can only be 1 at this stage.
287 */
288 int datareader_num_inputs(const DataReader *d){
289 return d->ninputs;
290 }
291
292 /**
293 Return the number of outputs (dependent variables) found in the DataReader's
294 current file. Should be one or more.
295 */
296 int datareader_num_outputs(const DataReader *d){
297 return d->noutputs;
298 }
299
300
301 int datareader_locate(DataReader *d, double t, double *t1, double *t2){
302 (*d->indepfn)(d,t1);
303 if(*t1 > t && d->i > 0){
304 /* start of current interval is too late */
305 do{
306 --(d->i);
307 (*d->indepfn)(d,t1);
308 /*CONSOLE_DEBUG("STEPPING BACK (d->i = %d currently), t1=%lf",d->i, *t1); */
309 }while(*t1 > t && d->i > 0);
310 }
311 /* now either d->i==0 or t1 < t*/
312 /* CONSOLE_DEBUG("d->i==%d, t1=%lf",d->i,*t1); */
313 ++d->i;
314 (*d->indepfn)(d,t2);
315 if(*t2 <= t){
316 /* end of current interface is too early */
317 do{
318 /* CONSOLE_DEBUG("STEPPING FORWARD (d->i = %d currently), t1=%lf, t2=%lf",d->i,*t1,*t2); */
319 (*d->indepfn)(d,t1);
320 ++(d->i);
321 (*d->indepfn)(d,t2);
322 }while(*t2 < t && d->i < d->ndata);
323 }
324 #if DR_DEBUG
325 CONSOLE_DEBUG("d->i==%d, t1[0] = %lf, t2[0] = %lf",d->i,t1[0],t2[0]);
326 #endif
327
328 if(d->i == d->ndata || d->i == 0){
329 return 1;
330 }
331
332 /* CONSOLE_DEBUG("INTERVAL OK"); */
333 return 0;
334 }
335
336 /**
337 Return an interpolated set of output values for the given input values.
338 This should be computed such that the output values are smooth in their
339 first derivatives.
340
341 The required memory for the inputs and outputs must be allocated by the
342 caller, and indicated by the pointers 'inputs' and 'outputs'.
343
344 @see datareader_deriv
345 @TODO implement this
346 */
347 int datareader_func(DataReader *d, double *inputs, double *outputs){
348 int i;
349 double t1[1], t2[1];
350 double v1[5], v2[5]; /** @TODO this is a fixed size... not good */
351
352 double t,g,dt;
353 t = inputs[0];
354
355 #if DR_DEBUG
356 CONSOLE_DEBUG("EVALUATING AT t = %lf",inputs[0]);
357 #endif
358
359 asc_assert(d->indepfn);
360
361 if(datareader_locate(d,t,t1,t2)){
362 CONSOLE_DEBUG("LOCATION ERROR");
363 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Time value t=%f is out of range",t);
364 return 1;
365 }
366
367 #if DR_DEBUG
368 CONSOLE_DEBUG("LOCATED AT t1 = %lf, t2 = %lf",t1[0], t2[0]);
369 #endif
370
371 (*d->valfn)(d,v2);
372 --d->i;
373 (*d->valfn)(d,v1);
374
375 #if DR_DEBUG
376 CONSOLE_DEBUG("LOCATED OK, d->i = %d, t1 = %lf, t2 = %lf, v1=%lf, v2=%lf", d->i, t1[0], t2[0],v1[0],v2[0]);
377 #endif
378
379 for(i=0;i<d->noutputs;++i){
380 dt = t2[0] - t1[0];
381 g = (v2[i]-v1[i])/dt;
382 outputs[i]=v1[i]+g*(t-(*t1));
383 #if DR_DEBUG
384 CONSOLE_DEBUG("[%d]: DT = %lf, START = %lf, GRADIENT = %lf, VALUE=%lf",i,dt, v1[i],g,outputs[i]);
385 #endif
386 }
387
388 return 0;
389 }
390
391 /**
392 Return an interpolated set of output derivatives for the given input
393 values. These should be smooth.
394 @see datareader_func
395 @TODO implement this
396 */
397 int datareader_deriv(DataReader *d, double *inputs, double *jacobian){
398 int i;
399 double t1[1], t2[1];
400 double v1[2], v2[2];
401
402 double t;
403 t = inputs[0];
404
405 /* CONSOLE_DEBUG("EVALUATING"); */
406
407 asc_assert(d->indepfn);
408
409 if(datareader_locate(d,t,t1,t2)){
410 CONSOLE_DEBUG("LOCATION ERROR");
411 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Time value t=%f is out of range",t);
412 return 1;
413 }
414
415 (*d->valfn)(d,v2);
416 --d->i;
417 (*d->valfn)(d,v1);
418
419 for(i=0;i<d->noutputs;++i){
420 jacobian[i]=(v2[i]-v1[i])/(*t2-*t1);
421 }
422
423 return 0;
424 }
425
426

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22