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

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