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

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