1 /* copyright 2016 Apache 2 sddekit authors */
5 typedef struct hist_data
7 /* nu+1 nu nu nu nd, maxvi */
8 uint32_t nd
, nu
, *lim
, *len
, *pos
, *uvi
, *vi
, *vi2i
, maxvi
;
10 double *buf
, *maxd
, *del
, dt
, t
;
13 uint32_t get_maxvi(sd_hist
*h
) { return ((hist_data
*) h
->ptr
)->maxvi
; }
14 uint32_t get_vi2i(sd_hist
*h
, uint32_t vi
) { return ((hist_data
*) h
->ptr
)->vi2i
[vi
]; }
16 static void update_time(sd_hist
*hist
, double new_t
)
19 hist_data
*h
= hist
->ptr
;
21 /* the current time must always be contained between
22 * pos and pos-1 in the buffer
24 * TODO handle case of irregular time step where new_t could
25 * be several h->dt ahead, and we need to fill in the buffer
29 while ((h
->t
+ h
->dt
) <= new_t
)
35 /* if no steps to take, return early */
39 /* update positions */
40 for (i
=0; i
<h
->nu
; i
++)
42 if (h
->pos
[i
] < n_steps
)
43 h
->pos
[i
] = h
->len
[i
] - n_steps
;
49 static void hist_free(sd_hist
*hist
)
51 hist_data
*h
= hist
->ptr
;
65 static sd_stat
fill(sd_hist
*hist
, sd_hfill
*hf
)
67 uint32_t i
, j
, ui
, o
, n
, *vi
;
70 hist_data
*h
= hist
->ptr
;
76 if ((t
= sd_malloc (sizeof(double) * n
))==NULL
||
77 (vi
= sd_malloc (sizeof(uint32_t) * n
))==NULL
) {
78 errmsg
= "failed to allocate memory for evaluating hist fill.";
82 /* expand indices per buffer element */
83 for (i
=0; i
<h
->nu
; i
++)
86 for (j
=h
->lim
[i
]; j
<h
->lim
[i
+1]; j
++)
90 /* evaluate time per buffer element */
91 for (i
=0; i
<h
->nu
; i
++)
93 for (j
=0; j
<(h
->len
[i
]-1); j
++)
95 o
= h
->pos
[i
]; /* current position in buffer */
96 o
+= j
; /* time step through buffer */
97 o
%= h
->len
[i
]; /* wrap around on section length */
98 o
+= h
->lim
[i
]; /* offset to start of section */
99 t
[o
] = h
->t
- j
* h
->dt
;
102 o
= h
->pos
[i
]; /* current position in buffer */
103 o
+= j
; /* time step through buffer */
104 o
%= h
->len
[i
]; /* wrap around on section length */
105 o
+= h
->lim
[i
]; /* offset to start of section */
106 t
[o
] = h
->t
+ h
->dt
; /* last point is next grid point */
109 if (hf
->apply(hf
, n
, t
, vi
, h
->buf
) != SD_OK
)
110 errmsg
= "history fill function failed.";
113 if (t
!=NULL
) sd_free(t
);
114 if (vi
!=NULL
) sd_free(vi
);
116 return errmsg
== NULL
? SD_OK
: SD_ERR
;
119 static void get(sd_hist
*hist
, double t
, double *aff
)
122 hist_data
*h
= hist
->ptr
;
127 for (i
= 0; i
< h
->nd
; i
++)
129 uint32_t ui
= h
->vi2i
[h
->vi
[i
]] /* unique variable index */
130 , p
= h
->pos
[ui
] /* rel pos in ui's var buf */
131 , l
= h
->len
[ui
] /* len of ui's var buf */
132 , o
= h
->lim
[ui
]; /* offset of ui's buf in h->buf */
134 /* TODO the following dt is not sol dt or hist dt, find better name */
135 double dt
= (t
- h
->del
[i
]) - (h
->t
- (l
- 2)*h
->dt
);
137 /* relative buffer indices */
138 int64_t i0
= (int64_t) ceil((l
- 2) - dt
/ h
->dt
);
141 int64_t i1
= i0
> 0 ? ((uint32_t) i0
) - 1 : l
- 1;
143 /* absolute buffer indices */
144 uint32_t i0_
= (p
+ i0
) % l
+ o
145 , i1_
= (p
+ i1
) % l
+ o
;
148 if ((i0_
< h
->lim
[ui
]) || (i0_
>= h
->lim
[ui
+1]))
149 sd_log_debug("[sd_hist_get] oob: i0_=%d not in [%d, %d) at %s:%d\n",
150 i0_
, h
->lim
[ui
], h
->lim
[ui
+1], __FILE__
, __LINE__
);
151 if ((i1_
< h
->lim
[ui
]) || (i1_
>= h
->lim
[ui
+1]))
152 sd_log_debug("[sd_hist_get] oob: i0_=%d not in [%d, %d) at %s:%d\n",
153 i1_
, h
->lim
[ui
], h
->lim
[ui
+1], __FILE__
, __LINE__
);
156 double y0
= h
->buf
[i0_
] /* consider sse read */
158 , m
= (y1
- y0
) / h
->dt
159 , dx
= (t
- h
->del
[i
]) - (h
->t
- i0
*h
->dt
);
161 aff
[i
] = m
* dx
+ y0
;
165 static void set(sd_hist
*hist
, double t
, double *eff
)
169 hist_data
*h
= hist
->ptr
;
171 update_time(hist
, t
);
173 for (i
=0; i
<h
->nu
; i
++)
176 i1
= i0
? i0
- 1 : h
->len
[i
] - 1;
180 if ((i0
< h
->lim
[i
]) || (i0
> h
->lim
[i
+1]))
181 fprintf(stderr
, "[sd_hist_set] t=%.3f ui=%d, i0=%d not in [%d,%d) %s:%d\n",
182 t
, i
, i0
, h
->lim
[i
], h
->lim
[i
+1], __FILE__
, __LINE__
);
183 if ((i1
< h
->lim
[i
]) || (i1
> h
->lim
[i
+1]))
184 fprintf(stderr
, "[sd_hist_set] t=%.3f ui=%d, i1=%d not in [%d,%d) %s:%d\n",
185 t
, i
, i1
, h
->lim
[i
], h
->lim
[i
+1], __FILE__
, __LINE__
);
192 sd_log_debug( "[sd_hist] unhandled dt<0 at %s:%d\n", __FILE__
, __LINE__
);
196 /* extrapolate from (x(h->t), x(t)) to next grid point*/
197 dx
= eff
[h
->vi2i
[h
->uvi
[i
]]] - h
->buf
[i0
];
198 h
->buf
[i1
] = (dx
/ dt
) * h
->dt
+ x0
;
200 /* reset grid point value */
201 h
->buf
[i0
] = eff
[h
->vi2i
[h
->uvi
[i
]]];
206 static uint32_t nbytes(sd_hist
*hist
)
209 hist_data
*h
= hist
->ptr
;
210 nb
= sizeof(sd_hist
) + sizeof(hist_data
);
211 nb
+= sizeof(uint32_t) * ((h
->nu
+1) + 3*h
->nu
+ h
->nd
+ h
->maxvi
);
212 nb
+= sizeof(double) * (h
->lim
[h
->nu
] + h
->nu
+ h
->nd
);
216 static uint32_t get_nu(sd_hist
*h
) {
217 return ((hist_data
*) h
->ptr
)->nu
;
220 static double get_buf_lin(sd_hist
*hist
, uint32_t index
)
222 hist_data
*h
= hist
->ptr
;
224 if (index
>= h
->lim
[h
->nu
])
225 sd_log_debug( "[hist->get_buf_lin] oob index=%d not in [0, %d)\n", index
, h
->lim
[h
->nu
] );
227 return h
->buf
[index
];
230 static double get_t(sd_hist
*h
) {
231 return ((hist_data
*) h
->ptr
)->t
;
234 static double get_dt(sd_hist
*h
) {
235 return ((hist_data
*) h
->ptr
)->dt
;
238 static uint32_t get_lim(sd_hist
*h
, uint32_t i
) {
239 return ((hist_data
*) h
->ptr
)->lim
[i
];
242 static uint32_t get_len(sd_hist
*h
, uint32_t i
) {
243 return ((hist_data
*) h
->ptr
)->len
[i
];
246 static uint32_t get_nd(sd_hist
*h
) {
247 return ((hist_data
*) h
->ptr
)->nd
;
250 static uint32_t get_pos(sd_hist
*h
, uint32_t i
) {
251 return ((hist_data
*) h
->ptr
)->pos
[i
];
254 static uint32_t get_uvi(sd_hist
*h
, uint32_t i
) {
255 return ((hist_data
*) h
->ptr
)->uvi
[i
];
258 static uint32_t get_vi(sd_hist
*h
, uint32_t i
) {
259 return ((hist_data
*) h
->ptr
)->vi
[i
];
262 static double get_maxd(sd_hist
*h
, uint32_t i
) {
263 return ((hist_data
*) h
->ptr
)->maxd
[i
];
266 static bool buf_is_null(sd_hist
*h
) {
267 return ((hist_data
*) h
->ptr
)->buf
== NULL
;
270 static double get_vd(sd_hist
*h
, uint32_t i
) {
271 return ((hist_data
*) h
->ptr
)->del
[i
];
274 static sd_hist sd_hist_defaults
= {
276 .get_maxvi
= &get_maxvi
,
277 .get_vi2i
= &get_vi2i
,
284 .get_buf_lin
= &get_buf_lin
,
292 .get_maxd
= &get_maxd
,
295 .buf_is_null
= &buf_is_null
298 static sd_stat
setup_buffer_structure(hist_data
*h
, double dt
)
305 (h
->maxd
= sd_malloc (sizeof(double) * h
->nu
))==NULL
||
306 (h
->lim
= sd_malloc (sizeof(double) * (h
->nu
+ 1)))==NULL
||
307 (h
->len
= sd_malloc (sizeof(double) * h
->nu
))==NULL
||
308 (h
->pos
= sd_malloc (sizeof(double) * h
->nu
))==NULL
310 errmsg
= "failed to alloc internal storage.";
313 /* vi2i requires max(uvi) then filling in vi2i[ui]=i */
315 for (i
=0; i
<h
->nu
; i
++)
316 if (h
->uvi
[i
] > h
->maxvi
)
317 h
->maxvi
= h
->uvi
[i
];
319 if ((h
->vi2i
= sd_malloc (sizeof(uint32_t) * (h
->maxvi
+ 1)))==NULL
) {
320 errmsg
= "failed to alloc internal storage.";
323 /* set up vi2i, maxd len pos lim */
324 for (i
=0; i
<h
->nu
; i
++)
329 for (j
=0; j
<h
->nd
; j
++)
330 if (h
->vi
[j
]==ui
&& h
->del
[j
]>maxd
)
333 h
->len
[i
] = (uint32_t) ceil(maxd
/ dt
) + 2;
338 h
->lim
[i
] = h
->lim
[i
-1] + h
->len
[i
-1];
340 h
->lim
[h
->nu
] = h
->lim
[h
->nu
-1] + h
->len
[h
->nu
-1];
343 if (h
->maxd
!=NULL
) sd_free(h
->maxd
);
344 if (h
->lim
!=NULL
) sd_free(h
->lim
);
345 if (h
->len
!=NULL
) sd_free(h
->len
);
346 if (h
->pos
!=NULL
) sd_free(h
->pos
);
347 if (h
->vi2i
!=NULL
) sd_free(h
->vi2i
);
353 sd_hist_new_default(uint32_t nd
, uint32_t *vi
, double *vd
, double t0
, double dt
)
356 hist_data
*h
= NULL
, zh
= { 0 };
357 if ((hist
= sd_malloc(sizeof(sd_hist
))) == NULL
358 || (h
= hist
->ptr
= sd_malloc(sizeof(hist_data
))) == NULL
359 || (*h
= zh
, (h
->nd
= nd
) < 1)
360 || sd_util_uniqi(nd
, vi
, &(h
->nu
), &(h
->uvi
)) != SD_OK
361 || (h
->del
= sd_malloc(sizeof(double) * nd
)) == NULL
362 || (h
->vi
= sd_malloc(sizeof(uint32_t) * nd
)) == NULL
363 || (memcpy(h
->del
, vd
, nd
* sizeof(double)),
364 memcpy(h
->vi
, vi
, nd
* sizeof(uint32_t)),
366 || setup_buffer_structure(h
, dt
) != SD_OK
367 || (h
->buf
= sd_malloc(sizeof(double) * h
->lim
[h
->nu
])) == NULL
370 if (hist
!= NULL
) sd_free(hist
);
373 if (h
->buf
!=NULL
) sd_free(h
->buf
);
374 if (h
->uvi
!=NULL
) sd_free(h
->uvi
);
375 if (h
->del
!=NULL
) sd_free(h
->del
);
376 if (h
->vi
!=NULL
) sd_free(h
->vi
);
378 sd_err("number of delays < 1 or memory alloc failed.");
383 *hist
= sd_hist_defaults
;
388 static sd_stat
val_fill_apply(sd_hfill
*hf
, uint32_t n
, double * restrict t
,
389 uint32_t *indices
, double * restrict buf
)
392 double value
= *((double*)hf
->ptr
);
393 (void)t
; (void)indices
;
394 for (i
= 0; i
< n
; i
++)
399 static void val_fill_free(sd_hfill
*hf
)
406 sd_hfill_new_val(double val
)
409 if ((hf
=sd_malloc(sizeof(sd_hfill
))) == NULL
410 || (hf
->ptr
=sd_malloc(sizeof(double))) == NULL
)
412 sd_err("alloc hfill failed.");
415 *((double*)hf
->ptr
) = val
;
416 hf
->free
= &val_fill_free
;
417 hf
->apply
= &val_fill_apply
;