1 /*============================================================================
2 * Notebook management.
3 *============================================================================*/
4
5 /*
6 This file is part of Code_Saturne, a general-purpose CFD tool.
7
8 Copyright (C) 1998-2021 EDF S.A.
9
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 details.
19
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22 Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24
25 /*----------------------------------------------------------------------------*/
26
27 #include "cs_defs.h"
28
29 /*----------------------------------------------------------------------------*/
30
31 /*----------------------------------------------------------------------------
32 * Standard C library headers
33 *----------------------------------------------------------------------------*/
34
35 #include <assert.h>
36 #include <ctype.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 /*----------------------------------------------------------------------------
42 * Local headers
43 *----------------------------------------------------------------------------*/
44
45 #include "bft_error.h"
46 #include "bft_mem.h"
47 #include "bft_printf.h"
48
49 #include "cs_gui_util.h"
50 #include "cs_log.h"
51 #include "cs_map.h"
52 #include "cs_parameters.h"
53
54 /*----------------------------------------------------------------------------
55 * Header for the current file
56 *----------------------------------------------------------------------------*/
57
58 #include "cs_notebook.h"
59
60 BEGIN_C_DECLS
61
62 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
63
64 /*=============================================================================
65 * Additional doxygen documentation
66 *============================================================================*/
67
68 #define _CS_NOTEBOOK_ENTRY_S_ALLOC_SIZE 16
69
70 /*============================================================================
71 * Structure definition
72 *============================================================================*/
73
74 typedef struct {
75
76 const char *name; /* Name of the notebook entry */
77
78 char *description; /* Description */
79
80 int id; /* Entry id */
81
82 cs_real_t val; /* Value of the entry */
83
84 int uncertain; /* Is is an uncertain variable ?
85 0: No
86 1: Yes, as input
87 2: Yes, as output */
88
89 bool editable; /* Can the value be modified */
90
91 } _cs_notebook_entry_t;
92
93 /*============================================================================
94 * Static global variables
95 *============================================================================*/
96
97 static int _n_entries = 0;
98 static int _n_entries_max = 0;
99 static int _n_uncertain_inputs = 0;
100 static int _n_uncertain_outputs = 0;
101
102 static _cs_notebook_entry_t **_entries = NULL;
103
104 static cs_map_name_to_id_t *_entry_map = NULL;
105
106 /*============================================================================
107 * Local functions
108 *============================================================================*/
109
110 /*----------------------------------------------------------------------------*/
111 /*!
112 * \brief Get a notebook entry by its name.
113 *
114 * Reruns the cs_notebook_entry_t object for a given name.
115 * If it does not exist, bft_error is called.
116 *
117 * \param[in] name notebook entry name
118 *
119 * \return _cs_notebook_entry_t pointer
120 */
121 /*----------------------------------------------------------------------------*/
122
123 static _cs_notebook_entry_t *
cs_notebook_entry_by_name(const char * name)124 cs_notebook_entry_by_name(const char *name)
125 {
126 int id = cs_map_name_to_id_try(_entry_map, name);
127
128 if (id > -1)
129 return _entries[id];
130 else {
131 bft_error(__FILE__, __LINE__, 0,
132 _("Entry \"%s\" is not defined."), name);
133 return NULL;
134 }
135 }
136
137 /*----------------------------------------------------------------------------*/
138 /*!
139 * \brief create a notebook entry
140 *
141 * Creates an entry in the notebook structure based on what the user provided
142 * in the GUI.
143 *
144 * \param[in] name name of the entry
145 * \param[in] uncertain flag (int) indicating if it is an uncertain input/output
146 * \param[in] editable flag (bool) indicating if the value can be modified
147 *
148 * \return a _cs_notebook_entry_t pointer
149 */
150 /*----------------------------------------------------------------------------*/
151
152 static _cs_notebook_entry_t *
_entry_create(const char * name,int uncertain,bool editable)153 _entry_create(const char *name,
154 int uncertain,
155 bool editable)
156 {
157 size_t l = strlen(name);
158 const char *addr_0 = NULL, *addr_1 = NULL;
159
160 /* Check that the name is not already used */
161 int id = cs_map_name_to_id_try(_entry_map, name);
162 if (id > -1)
163 bft_error(__FILE__, __LINE__, 0,
164 _("Error creating entry:\n"
165 " name: \"%s\"\n\n"
166 "An entry with that name has already been defined:\n"
167 " id: %d\n"),
168 name, id);
169
170 /* Initialize the map is necessary */
171 if (_entry_map == NULL)
172 _entry_map = cs_map_name_to_id_create();
173
174 else
175 addr_0 = cs_map_name_to_id_reverse(_entry_map, 0);
176
177 if (l == 0)
178 bft_error(__FILE__, __LINE__, 0, _("Defining an entry requires a name."));
179
180 /* Insert the entry in map */
181 int entry_id = cs_map_name_to_id(_entry_map, name);
182
183 /* Move name pointers of previous entries if necessary */
184 addr_1 = cs_map_name_to_id_reverse(_entry_map, 0);
185
186 if (addr_1 != addr_0) {
187 int i;
188 ptrdiff_t addr_shift = addr_1 - addr_0;
189 for (i = 0; i < entry_id; i++)
190 _entries[i]->name += addr_shift;
191 }
192
193 if (entry_id == _n_entries)
194 _n_entries = entry_id + 1;
195
196 /* Reallocate entries pointer if necessary */
197 if (_n_entries > _n_entries_max) {
198 if (_n_entries_max == 0)
199 _n_entries_max = 8;
200 else
201 _n_entries_max *= 2;
202 BFT_REALLOC(_entries, _n_entries_max, _cs_notebook_entry_t *);
203 }
204
205 /* Allocate entries descriptor block if necessary (same as for cs_field_t) */
206 int shift_in_alloc_block = entry_id % _CS_NOTEBOOK_ENTRY_S_ALLOC_SIZE;
207 if (shift_in_alloc_block == 0)
208 BFT_MALLOC(_entries[entry_id],
209 _CS_NOTEBOOK_ENTRY_S_ALLOC_SIZE,
210 _cs_notebook_entry_t);
211
212 else
213 _entries[entry_id] = _entries[entry_id - shift_in_alloc_block]
214 + shift_in_alloc_block;
215
216 /* Assign the entry */
217 _cs_notebook_entry_t *e = _entries[entry_id];
218
219 e->name = cs_map_name_to_id_reverse(_entry_map, entry_id);
220
221 e->id = entry_id;
222
223 e->val = 0.;
224
225 e->uncertain = uncertain;
226 if (uncertain == 0)
227 _n_uncertain_inputs += 1;
228 else if (uncertain == 1)
229 _n_uncertain_outputs += 1;
230
231 e->editable = editable;
232
233 return e;
234 }
235
236 /*----------------------------------------------------------------------------*/
237 /*!
238 * \brief Set the entry description
239 *
240 * Set the description of the notebook parameter.
241 *
242 * \param[in] e pointer to _cs_notebook_entry_t
243 * \param[in] description description of the entry
244 */
245 /*----------------------------------------------------------------------------*/
246
247 static void
_entry_set_description(_cs_notebook_entry_t * e,const char * description)248 _entry_set_description(_cs_notebook_entry_t *e,
249 const char *description)
250 {
251
252 int l = strlen(description);
253 BFT_MALLOC(e->description, l+1, char);
254 if (l == 0)
255 strcpy(e->description, "");
256 else
257 strcpy(e->description, description);
258 }
259
260 /*----------------------------------------------------------------------------*/
261 /*!
262 * \brief Set the entry value
263 *
264 * Set the value of the notebook parameter.
265 *
266 * \param[in] e pointer to _cs_notebook_entry_t
267 * \param[in] value value to set to the entry
268 */
269 /*----------------------------------------------------------------------------*/
270
271 static void
_entry_set_value(_cs_notebook_entry_t * e,cs_real_t value)272 _entry_set_value(_cs_notebook_entry_t *e,
273 cs_real_t value)
274 {
275 e->val = value;
276 }
277
278 /*! (DOXYGEN_SHOULD_SKIP_THIS) \endcond */
279
280 /*============================================================================
281 * Public function definitions
282 *============================================================================*/
283
284 /*----------------------------------------------------------------------------*/
285 /*!
286 * \brief Initialize the notebook object (based on cs_tree_node_t).
287 */
288 /*----------------------------------------------------------------------------*/
289
290 void
cs_notebook_load_from_file(void)291 cs_notebook_load_from_file(void)
292 {
293 const char na[] = "NA";
294
295 cs_tree_node_t *tnb = cs_tree_get_node(cs_glob_tree,
296 "physical_properties/notebook");
297 for (cs_tree_node_t *n = cs_tree_find_node(tnb, "var");
298 n != NULL;
299 n = cs_tree_node_get_next_of_name(n)) {
300
301 const char *name = cs_tree_node_get_tag(n, "name");
302 const char *oturns = cs_tree_node_get_tag(n, "oturns");
303 const char *d = cs_tree_node_get_tag(n, "description");
304 const char *c_val = cs_tree_node_get_tag(n, "value");
305 const char *c_edit = cs_tree_node_get_tag(n, "editable");
306
307 if (d == NULL)
308 d = na;
309 else if (strlen(d) == 0)
310 d = na;
311
312 int uncertain = -1;
313 const char *uncertain_c = "No";
314 if (oturns != NULL) {
315 if (strcmp(oturns, "Yes: Input") == 0) {
316 uncertain = 0;
317 uncertain_c = "Input";
318 } else if (strcmp(oturns, "Yes: Output") == 0) {
319 uncertain = 1;
320 uncertain_c = "Output";
321 }
322 }
323 bool editable = false;
324 if (c_edit != NULL)
325 if (strcmp(c_edit, "Yes") == 0)
326 editable = true;
327
328 /* If the variable is uncertain then :
329 * - an input cannot be modifed, hence editable = false
330 * - an output has to be modified by the code, hence editable=true
331 *
332 * If the user specified a different status, a warning is printed
333 */
334 if (uncertain > -1) {
335 if (editable != uncertain)
336 bft_printf(_(" Warning: You defined the parameter %s as an uncertain "
337 "of type %s with an incompatbile editable state of %d.\n"
338 " Editable state is set to %d\n"),
339 name, uncertain_c, editable, uncertain);
340 editable = uncertain;
341 }
342
343 _cs_notebook_entry_t *e = _entry_create(name, uncertain, editable);
344
345 _entry_set_description(e, d);
346 cs_real_t val = atof(c_val);
347 _entry_set_value(e, val);
348
349 }
350 cs_notebook_log();
351 }
352
353 /*----------------------------------------------------------------------------*/
354 /*!
355 * \brief Check if a parameter value is present.
356 *
357 * \param[in] name name of the parameter
358 * \param[out] editable 1 if the value is editable, 0 otherwise (optional)
359 *
360 * \return 0 if not present, 1 if present
361 */
362 /*----------------------------------------------------------------------------*/
363
364 int
cs_notebook_parameter_is_present(const char * name,int * editable)365 cs_notebook_parameter_is_present(const char *name,
366 int *editable)
367 {
368 int retval = 0;
369 int id = cs_map_name_to_id_try(_entry_map, name);
370
371 if (editable != NULL)
372 *editable = 0;
373
374 if (id > -1) {
375 retval = 1;
376 if (editable != NULL) {
377 if (_entries[id]->editable)
378 *editable = 1;
379 }
380 }
381 return retval;
382 }
383
384 /*----------------------------------------------------------------------------*/
385 /*!
386 * \brief Return a parameter value (real).
387 *
388 * The name used is the same as the one in the GUI.
389 *
390 * \param[in] name name of the parameter
391 *
392 * \return value of the given parameter
393 */
394 /*----------------------------------------------------------------------------*/
395
396 cs_real_t
cs_notebook_parameter_value_by_name(const char * name)397 cs_notebook_parameter_value_by_name(const char *name)
398 {
399 _cs_notebook_entry_t *e = cs_notebook_entry_by_name(name);
400 return e->val;
401 }
402
403 /*----------------------------------------------------------------------------*/
404 /*!
405 * \brief Set a parameter value (real) for an editable parameter.
406 *
407 * The name used is the same as the one in the GUI.
408 *
409 * \param[in] name name of the parameter
410 * \param[in] val value of the parameter
411 */
412 /*----------------------------------------------------------------------------*/
413
414 void
cs_notebook_parameter_set_value(const char * name,cs_real_t val)415 cs_notebook_parameter_set_value(const char *name,
416 cs_real_t val)
417 {
418 _cs_notebook_entry_t *e = cs_notebook_entry_by_name(name);
419
420 if (e->editable == false)
421 bft_error(__FILE__, __LINE__, 0,
422 _("Entry \"%s\" was defined as not editable in the notebook.\n"),
423 e->name);
424
425 _entry_set_value(e, val);
426 }
427
428 /*----------------------------------------------------------------------------*/
429 /*!
430 * \brief Indicate whether the parameter is used for a study with openturns.
431 *
432 * Returns an int flag to indicate whether this paramter is used for an
433 * OpenTurns study.
434 * -1 : The parameter is not used with OpenTurns
435 * 0 : The parameter is used as an input from OpenTurns
436 * 1 : The parameter is used as an output to OpenTurns
437 *
438 * \param[in] name name of the parameter
439 *
440 * \return an int flag value
441 */
442 /*----------------------------------------------------------------------------*/
443
444 int
cs_notebook_parameter_get_openturns_status(char * name)445 cs_notebook_parameter_get_openturns_status(char *name)
446 {
447 _cs_notebook_entry_t *e = cs_notebook_entry_by_name(name);
448 return e->uncertain;
449 }
450
451 /*----------------------------------------------------------------------------*/
452 /*!
453 * \brief Returns the description of the parameter (GUI defined).
454 *
455 * \param[in] name name of the parameter
456 *
457 * \return a const char pointer containing the description.
458 */
459 /*----------------------------------------------------------------------------*/
460
461 const char *
cs_notebook_parameter_get_description(char * name)462 cs_notebook_parameter_get_description(char *name)
463 {
464 _cs_notebook_entry_t *e = cs_notebook_entry_by_name(name);
465 return e->description;
466 }
467
468 /*----------------------------------------------------------------------------*/
469 /*!
470 * \brief Destroy the notebook structure.
471 *
472 * Destroys the structures related to the notebook.
473 */
474 /*----------------------------------------------------------------------------*/
475
476 void
cs_notebook_destroy_all(void)477 cs_notebook_destroy_all(void)
478 {
479 /* Before destruction, we dump the results */
480 cs_notebook_uncertain_output();
481
482 for (int i = 0; i < _n_entries; i++) {
483 _cs_notebook_entry_t *e = _entries[i];
484 BFT_FREE(e->description);
485 }
486
487 for (int i = 0; i < _n_entries; i++) {
488 if (i % _CS_NOTEBOOK_ENTRY_S_ALLOC_SIZE == 0)
489 BFT_FREE(_entries[i]);
490 }
491
492 BFT_FREE(_entries);
493
494 cs_map_name_to_id_destroy(&_entry_map);
495
496 _n_entries = 0;
497 _n_entries_max = 0;
498 }
499
500 /*----------------------------------------------------------------------------*/
501 /*!
502 * \brief Output the notebook info to the setup log.
503 */
504 /*----------------------------------------------------------------------------*/
505
506 void
cs_notebook_log(void)507 cs_notebook_log(void)
508 {
509 if (_n_entries == 0)
510 return;
511
512 cs_log_t l = CS_LOG_SETUP;
513
514 cs_log_printf(l, _("Notebook:\n"
515 "---------\n"));
516 for (int i = 0; i < _n_entries; i++)
517 cs_log_printf(l, _("\n"
518 " Entry #%d\n"
519 " name: %s\n"
520 " description: %s\n"
521 " uncertain: %d\n"
522 " editable: %d\n"
523 " value: %f\n"),
524 i,
525 _entries[i]->name,
526 _entries[i]->description,
527 _entries[i]->uncertain,
528 _entries[i]->editable,
529 _entries[i]->val);
530
531 cs_log_printf(l, "\n");
532 cs_log_separator(l);
533 }
534
535 /*----------------------------------------------------------------------------*/
536 /*!
537 * \brief Write uncertain values to output file.
538 *
539 * If input and output uncertain variables are provided, output values
540 * are written to an output file: cs_uncertain_output.dat
541 * Results are ordered in the definition order in the notebook.
542 */
543 /*----------------------------------------------------------------------------*/
544
545 void
cs_notebook_uncertain_output(void)546 cs_notebook_uncertain_output(void)
547 {
548 if (_n_uncertain_inputs == 0 || _n_uncertain_outputs == 0)
549 return;
550
551 if (cs_glob_rank_id <= 0) {
552 FILE *file = fopen("cs_uncertain_output.dat", "w");
553
554 /* Write header */
555 fprintf(file, "#");
556 for (int i = 0; i < _n_entries; i++) {
557 if (_entries[i]->uncertain == 1)
558 fprintf(file, " %s", _entries[i]->name);
559 }
560 fprintf(file, "\n");
561
562 /* Write values */
563 int count = 0;
564 for (int i = 0; i < _n_entries; i++) {
565 if (_entries[i]->uncertain == 1) {
566 if (count == 0)
567 count += 1;
568 else
569 fprintf(file, ", ");
570
571 fprintf(file, "%f", _entries[i]->val);
572 }
573 }
574 fflush(file);
575 fclose(file);
576 }
577 }
578
579 /*----------------------------------------------------------------------------*/
580
581 END_C_DECLS
582