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