sdis_estimator_buffer.c (7444B)
1 /* Copyright (C) 2016-2025 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "sdis.h" 17 #include "sdis_device_c.h" 18 #include "sdis_estimator_c.h" 19 #include "sdis_estimator_buffer_c.h" 20 #include "sdis_log.h" 21 22 #include <star/ssp.h> 23 24 struct sdis_estimator_buffer { 25 struct sdis_estimator** estimators; /* Row major per pixel estimators */ 26 size_t width; 27 size_t height; 28 29 struct accum temperature; 30 struct accum realisation_time; 31 size_t nrealisations; /* #successes */ 32 size_t nfailures; 33 34 /* State of the RNG after the simulation */ 35 struct ssp_rng* rng; 36 37 ref_T ref; 38 struct sdis_device* dev; 39 }; 40 41 /******************************************************************************* 42 * Helper functions 43 ******************************************************************************/ 44 static void 45 estimator_buffer_release(ref_T* ref) 46 { 47 struct sdis_estimator_buffer* buf; 48 struct sdis_device* dev; 49 size_t i; 50 ASSERT(ref); 51 52 buf = CONTAINER_OF(ref, struct sdis_estimator_buffer, ref); 53 dev = buf->dev; 54 55 if(buf->estimators) { 56 FOR_EACH(i, 0, buf->width*buf->height) { 57 if(buf->estimators[i]) SDIS(estimator_ref_put(buf->estimators[i])); 58 } 59 MEM_RM(dev->allocator, buf->estimators); 60 } 61 62 if(buf->rng) SSP(rng_ref_put(buf->rng)); 63 MEM_RM(dev->allocator, buf); 64 SDIS(device_ref_put(dev)); 65 } 66 67 /******************************************************************************* 68 * Exported functions 69 ******************************************************************************/ 70 res_T 71 sdis_estimator_buffer_ref_get(struct sdis_estimator_buffer* buf) 72 { 73 if(!buf) return RES_BAD_ARG; 74 ref_get(&buf->ref); 75 return RES_OK; 76 } 77 78 res_T 79 sdis_estimator_buffer_ref_put(struct sdis_estimator_buffer* buf) 80 { 81 if(!buf) return RES_BAD_ARG; 82 ref_put(&buf->ref, estimator_buffer_release); 83 return RES_OK; 84 } 85 86 res_T 87 sdis_estimator_buffer_get_definition 88 (const struct sdis_estimator_buffer* buf, size_t definition[2]) 89 { 90 if(!buf || !definition) return RES_BAD_ARG; 91 definition[0] = buf->width; 92 definition[1] = buf->height; 93 return RES_OK; 94 } 95 96 res_T 97 sdis_estimator_buffer_at 98 (const struct sdis_estimator_buffer* buf, 99 const size_t x, 100 const size_t y, 101 const struct sdis_estimator** estimator) 102 { 103 if(!buf || x >= buf->width || y >= buf->height || !estimator) 104 return RES_BAD_ARG; 105 *estimator = estimator_buffer_grab(buf, x, y); 106 return RES_OK; 107 } 108 109 res_T 110 sdis_estimator_buffer_get_realisation_count 111 (const struct sdis_estimator_buffer* buf, size_t* nrealisations) 112 { 113 if(!buf || !nrealisations) return RES_BAD_ARG; 114 *nrealisations = buf->nrealisations; 115 return RES_OK; 116 } 117 118 res_T 119 sdis_estimator_buffer_get_failure_count 120 (const struct sdis_estimator_buffer* buf, size_t* nfailures) 121 { 122 if(!buf || !nfailures) return RES_BAD_ARG; 123 *nfailures = buf->nfailures; 124 return RES_OK; 125 } 126 127 #define SETUP_MC(Mc, Acc) { \ 128 (Mc)->E = (Acc)->sum / (double)(Acc)->count; \ 129 (Mc)->V = (Acc)->sum2 / (double)(Acc)->count - (Mc)->E*(Mc)->E; \ 130 (Mc)->V = MMAX((Mc)->V, 0); \ 131 (Mc)->SE = sqrt((Mc)->V / (double)(Acc)->count); \ 132 } (void)0 133 134 res_T 135 sdis_estimator_buffer_get_temperature 136 (const struct sdis_estimator_buffer* buf, struct sdis_mc* mc) 137 { 138 if(!buf || !mc) return RES_BAD_ARG; 139 SETUP_MC(mc, &buf->temperature); 140 return RES_OK; 141 } 142 143 res_T 144 sdis_estimator_buffer_get_realisation_time 145 (const struct sdis_estimator_buffer* buf, struct sdis_mc* mc) 146 { 147 if(!buf || !mc) return RES_BAD_ARG; 148 SETUP_MC(mc, &buf->realisation_time); 149 return RES_OK; 150 } 151 152 res_T 153 sdis_estimator_buffer_get_rng_state 154 (const struct sdis_estimator_buffer* buf, struct ssp_rng** rng_state) 155 { 156 if(!buf || !rng_state) return RES_BAD_ARG; 157 *rng_state = buf->rng; 158 return RES_OK; 159 } 160 161 #undef SETUP_MC 162 163 /******************************************************************************* 164 * Local functions 165 ******************************************************************************/ 166 res_T 167 estimator_buffer_create 168 (struct sdis_device* dev, 169 const size_t width, 170 const size_t height, 171 struct sdis_estimator_buffer** out_buf) 172 { 173 struct sdis_estimator_buffer* buf = NULL; 174 size_t i; 175 res_T res = RES_OK; 176 177 if(!dev || !width || !height || !out_buf) { 178 res = RES_BAD_ARG; 179 goto error; 180 } 181 182 buf = MEM_CALLOC(dev->allocator, 1, sizeof(*buf)); 183 if(!buf) { res = RES_MEM_ERR; goto error; } 184 185 ref_init(&buf->ref); 186 SDIS(device_ref_get(dev)); 187 buf->dev = dev; 188 buf->width = width; 189 buf->height = height; 190 191 buf->estimators = MEM_CALLOC 192 (dev->allocator, width*height, sizeof(*buf->estimators)); 193 if(!buf->estimators) { 194 log_err(dev, "%s: could not allocate a buffer of estimators of %lux%lu.\n", 195 FUNC_NAME, (unsigned long)width, (unsigned long)height); 196 res = RES_MEM_ERR; 197 goto error; 198 } 199 200 FOR_EACH(i, 0, width*height) { 201 res = estimator_create(dev, SDIS_ESTIMATOR_TEMPERATURE, buf->estimators+i); 202 if(res != RES_OK) goto error; 203 } 204 205 exit: 206 if(out_buf) *out_buf = buf; 207 return res; 208 error: 209 if(buf) { 210 SDIS(estimator_buffer_ref_put(buf)); 211 buf = NULL; 212 } 213 goto exit; 214 } 215 216 struct sdis_estimator* 217 estimator_buffer_grab 218 (const struct sdis_estimator_buffer* buf, 219 const size_t x, 220 const size_t y) 221 { 222 ASSERT(x < buf->width && y < buf->height); 223 return buf->estimators[y*buf->width + x]; 224 } 225 226 void 227 estimator_buffer_setup_realisations_count 228 (struct sdis_estimator_buffer* buf, 229 const size_t nrealisations, 230 const size_t nsuccesses) 231 { 232 ASSERT(buf && nrealisations && nsuccesses && nsuccesses<=nrealisations); 233 buf->nrealisations = nsuccesses; 234 buf->nfailures = nrealisations - nsuccesses; 235 } 236 237 void 238 estimator_buffer_setup_temperature 239 (struct sdis_estimator_buffer* buf, 240 const double sum, 241 const double sum2) 242 { 243 ASSERT(buf && buf->nrealisations); 244 buf->temperature.sum = sum; 245 buf->temperature.sum2 = sum2; 246 buf->temperature.count = buf->nrealisations; 247 } 248 249 void 250 estimator_buffer_setup_realisation_time 251 (struct sdis_estimator_buffer* buf, 252 const double sum, 253 const double sum2) 254 { 255 ASSERT(buf && buf->nrealisations); 256 buf->realisation_time.sum = sum; 257 buf->realisation_time.sum2 = sum2; 258 buf->realisation_time.count = buf->nrealisations; 259 } 260 261 res_T 262 estimator_buffer_save_rng_state 263 (struct sdis_estimator_buffer* buf, 264 const struct ssp_rng_proxy* proxy) 265 { 266 ASSERT(buf && proxy); 267 268 /* Release the previous RNG state if any */ 269 if(buf->rng) { 270 SSP(rng_ref_put(buf->rng)); 271 buf->rng = NULL; 272 } 273 return create_rng_from_rng_proxy(buf->dev, proxy, &buf->rng); 274 } 275 276 /* Define the functions generic to the observable type */ 277 #define SDIS_X_OBS probe 278 #include "sdis_estimator_buffer_X_obs.h" 279 #define SDIS_X_OBS probe_boundary 280 #include "sdis_estimator_buffer_X_obs.h"