stardis-green

Post-processing of green functions
git clone git://git.meso-star.fr/stardis-green.git
Log | Files | Refs | README | LICENSE

commit 1fad7bc43ce62dd0b3db024032a01b2396080b4a
parent fdd2431a225245debc5df9119953058b3807f21f
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri, 20 Nov 2020 09:23:13 +0100

Merge branch 'release_0.1'

Diffstat:
MREADME.md | 8+++-----
Mcmake/CMakeLists.txt | 7+++++--
Mcmake/doc/CMakeLists.txt | 6+++---
Mdoc/sgreen-input.5.txt | 67+++++++++++++++++++++++++++++++++----------------------------------
Mdoc/sgreen-output.5.txt | 19++++++++-----------
Mdoc/sgreen.1.txt.in | 22+++++++++++-----------
Msrc/green-args.c | 2+-
Msrc/green-args.h | 2--
Msrc/green-compute.c | 527+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/green-compute.h | 4+---
Msrc/green-input.c | 49++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/green-main.c | 57+++++++++++++++++++++++++++++++++++++++++----------------
Msrc/green-output.c | 248+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/green-output.h | 8++++++++
Msrc/green-types.h | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
15 files changed, 795 insertions(+), 354 deletions(-)

diff --git a/README.md b/README.md @@ -26,7 +26,6 @@ variable the install directories of its dependencies. ### Version 0.1 -Postprocess a binary Green function file, as created by stardis. Main features are: - -- produce a summary of a Green function in HTML format, -- apply a Green function to new settings and output the corresponding Monte-Carlo results. -\ No newline at end of file +- Compatible with stardis v0.5.0 binary Green function files. +- Can produce a summary of a Green function in HTML format. +- Can apply a Green function to new settings and output the corresponding Monte-Carlo results. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -19,7 +19,7 @@ project(sgreen C) set(GREEN_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) if(CMAKE_HOST_UNIX) - set(GREEN_DOC "TROFF & HTML" CACHE STRING + set(GREEN_DOC "TROFF" CACHE STRING "Type of documentation to generate and install.") else() set(GREEN_DOC "HTML" CACHE STRING @@ -56,6 +56,7 @@ configure_file(${GREEN_SOURCE_DIR}/green-version.h.in ############################################################################### find_package(RCMake 0.4 REQUIRED) find_package(RSys 0.9 REQUIRED) +find_package(OpenMP 2.0 REQUIRED) if(MSVC) find_package(MuslGetopt REQUIRED) endif() @@ -116,11 +117,13 @@ add_executable(sgreen if(CMAKE_COMPILER_IS_GNUCC) set(MATH_LIB m) set_target_properties(sgreen PROPERTIES - COMPILE_FLAGS "-std=c99" + COMPILE_FLAGS "-std=c99 ${OpenMP_C_FLAGS}" + LINK_FLAGS "${OpenMP_C_FLAGS}" VERSION ${GREEN_VERSION}) elseif(MSVC) set(GETOPT_LIB MuslGetopt) set_target_properties(sgreen PROPERTIES + COMPILE_FLAGS ${OpenMP_C_FLAGS} VERSION ${GREEN_VERSION}) endif() diff --git a/cmake/doc/CMakeLists.txt b/cmake/doc/CMakeLists.txt @@ -113,7 +113,7 @@ if(_html) -bxhtml11 -dmanpage --attribute themedir=${GREEN_DOC_DIR} - --theme=green-man) + --theme=sgreen-man) set(MAN_FILES) set(MAN5_FILES) @@ -143,7 +143,7 @@ if(_html) endforeach() add_custom_target(man-html ALL DEPENDS ${MAN_FILES}) - install(FILES ${MAN1_FILES} DESTINATION share/man/man1) - install(FILES ${MAN5_FILES} DESTINATION share/man/man5) + install(FILES ${MAN1_FILES} DESTINATION share/doc/sgreen/html) + install(FILES ${MAN5_FILES} DESTINATION share/doc/sgreen/html) endif() diff --git a/doc/sgreen-input.5.txt b/doc/sgreen-input.5.txt @@ -20,29 +20,26 @@ sgreen-input(5) NAME ---- -green-input - settings description for green(1) +sgreen-input - settings description for sgreen(1) DESCRIPTION ----------- -*green-input* is the format used by the *green*(1) program to describe a +*sgreen-input* is the format used by the *sgreen*(1) program to describe settings when applying a Green function. It relies on a line-based ad-hoc syntax. A settings file is composed of lines of text, each one describing the settings -to apply for a Green function call. Each line contains *variable = value" pairs +to apply for a Green function call. Each line contains *variable = value* pairs in any number (at least one pair for a line to be meaningful). A list of all legit variable names can be found in the Green function summary, as produced -by option *-s*. +by *sgreen*(1) option *-s*. GRAMMAR ------- -In what follows, some lines end in *\*. This is used as a convenience to -continue a description next line. However, this trick cannot be used in -actual description files and actual description lines must be kept single-line. -Also, text appearing between quote marks has to be used verbatim in the input, -except the quote characters. Finally, text introduced by the *#* character in -descriptions, when not verbatim, is a comment and is not part of the -description. +In what follows, text appearing between quote marks has to be used verbatim in +the input, except the quote characters. Also, text introduced by the *#* +character in descriptions, when not verbatim, is a comment and is not part of +the description. [verse] _______ @@ -68,36 +65,38 @@ _______ ______________ -TRIANGLE SIDES --------------- -Side descriptions in side specifiers rely on the following convention: we -first consider the direct triangle's normal (right-hand rule), then we define -the BACK side of a triangle to be the side this normal comes out from. That -means that a closed set of triangles with normals pointing outside should be -used with the FRONT side specifier to describe inside medium. - NAMES ----- -Names, either file names, medium names or boundary names, are a sequence of -one or ore ASCII characters, including numbers and special characters like -*.* *_* *-* as one may consider using in standard file names, *without any -spacing* either escaped or not. Two different description lines cannot use -the same name. +Except the name AMBIENT, that refers to the ambient radiative temperature and +is always a legit name in settings, the list of names that can be used to form +settings is the list of medium and boundary case-sensitive names defined in the +*stardis-input*(5) files used when creating the Green function applied to the +settings. + +UNITS +----- +Any physical quantity involved in settings files is expected in the +International System of Units (metre, kelvin, Watt). EXAMPLES -------- -Define a solid named Cube with a h boundary. The cube geometry is read from -the file cube.stl and the solid medium properties are lambda=0.1, rho=25, cp=2. -The numerical parameter delta, that is used for solid conductive walks, is -0.05. The initial temperature of the cube is 0°K and its volumic power is 0. -The boundary properties are emisivity=0, specular-fraction=0, h=10 and -external-temperature = 100°K. +Apply a Green function with *AMBIENT* radiative temperature set to 0 K. +....... +AMBIENT = 0 +....... + +First apply a Green function with volumic power in medium *AL* set to 100 W/m^3^ +and temperature of the *Left* boundary set to 300 K. Then apply it with the +same variables set to 120 and 350 respectively. Finally, apply it with the +same variables set to 140 and 360 respectively and temperature of the *Right* +boundary set to 380 K. ....... -SOLID Cube 0.1 25 2 0.05 0 0 FRONT cube.stl -H_BOUNDARY_FOR_SOLID HdT 0 0 10 100 cube.stl +AL.VP=100 Left.T=300 +AL.VP=120 Left.T=350 +AL.VP=140 Left.T=360 Right.T=380 ....... SEE ALSO -------- -*green*(1), -*green-input*(5) +*sgreen*(1), +*sgreen-input*(5) diff --git a/doc/sgreen-output.5.txt b/doc/sgreen-output.5.txt @@ -20,24 +20,21 @@ sgreen-output(5) NAME ---- -green-output - output format of green(1) results +sgreen-output - output format of sgreen(1) results DESCRIPTION ----------- -*green-output* describes the output format of option *-a* of the *green*(1) -program. - The type of the data that are generated depends on the options used when -*green*(1) is invoked. When invoked with the option *-a*, *green*(1) outputs +*sgreen*(1) is invoked. When invoked with option *-a*, *sgreen*(1) outputs Monte-Carlo results, either in extended or compact format, whether option *-e* -is used or not. Also, when invoked whith option *-s* *green*(1) outputs an +is used or not. Also, when invoked whith option *-s* *sgreen*(1) outputs an HTML file contening a summary of the Green function used. GRAMMAR ------- As Green summaries comply with HTML format, that can be found in HTML -specification documents [1], they will not be further described. Only -Monte-Carlo results are described in this section. +specification documents [1], they will not be further described thereafter. +Only Monte-Carlo results grammar is described in this section. In what follows, text appearing between quote marks is a verbatim part of the output, except the quote characters, and text introduced by the *#* character @@ -67,7 +64,7 @@ _______ HTML SUMMARY ------------ -When using option *-s*, *green*(1) creates a summary of the Green function in +When using option *-s*, *sgreen*(1) creates a summary of the Green function in HTML format. This document contains the following sections: * List of variables @@ -98,5 +95,5 @@ NOTES SEE ALSO -------- -*green*(1), -*green-input*(5) +*sgreen*(1), +*sgreen-input*(5) diff --git a/doc/sgreen.1.txt.in b/doc/sgreen.1.txt.in @@ -30,17 +30,17 @@ SYNOPSIS DESCRIPTION ----------- *sgreen* is a post processing tool that can be used on *stardis*(1) Green -functions, as contained in binary green files. The main functionality is to -apply different boundary conditions to a system once solved by *stardis*(1) -in Green mode (*-G* option of *stardis*(1)). The provided file should comply -with the *sgreen-input*(5) format, that is also the output format of -*stardis*(1) in binary Green mode (see *stardis-output*(5)). +functions (a.k.a propagators), as contained in binary files. The main +functionality is to apply different boundary conditions to a system once solved +by *stardis*(1) in Green mode (*-G* option of *stardis*(1)). The provided file +should comply with the *sgreen-input*(5) format, that is also the +*stardis-output*(1) format in binary Green mode. -Using this Green function (a.k.a propagator) approach, when possible, produces -the very same results as a full Monte-Carlo computation, but only requires a -fraction of the computation time. +Using this Green function approach, when possible, produces the very same +results as a full Monte-Carlo computation, but only requires a fraction of the +computation time. -The propagator is of great value for thermicist engineers as it gives some +The propagator is of great value to thermal engineers as it gives some crucial information to analyse heat transfers in the system. It helps engineers answer questions like _"Where from does the heat come at this location?"_. Propagators seamlessly agregate all the provided geometrical and physical @@ -53,7 +53,7 @@ simulated system. OPTIONS ------- *-a* _FILE_NAME_:: - Apply a Green function using the variable settings read in a file. Can only + Apply a Green function using the variable settings read from a file. Can only be applied in conjunction with option *-g*. *-e*:: @@ -101,7 +101,7 @@ Create a summary of the *heatsink.green* Green function and write it in the *heatsink_settings.txt* and output the corresponding Monte-Carlo results to stdout in compact format. - $ sgreen -g heatsink.green -s heatsink_green.html -a heatsink_green.html + $ sgreen -g heatsink.green -s heatsink_green.html -a heatsink_settings.txt COPYRIGHT --------- diff --git a/src/green-args.c b/src/green-args.c @@ -56,7 +56,7 @@ init_args args->command_filename = NULL; args->green_filename = NULL; args->info_filename = NULL; - args->nthreads = DEFAULT_NTHREADS; + args->nthreads = (unsigned)omp_get_num_procs(); args->verbose = GREEN_DEFAULT_VERBOSE_LEVEL; } diff --git a/src/green-args.h b/src/green-args.h @@ -22,8 +22,6 @@ struct logger; struct mem_allocator; struct args; -#define DEFAULT_NTHREADS UINT_MAX - struct args { struct logger* logger; struct mem_allocator* allocator; diff --git a/src/green-compute.c b/src/green-compute.c @@ -13,14 +13,72 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#define _POSIX_C_SOURCE 200112L /* strtok_r */ + +#include "green-compute.h" #include "green-types.h" #include <rsys/str.h> #include <rsys/cstr.h> #include <rsys/logger.h> #include <rsys/text_reader.h> +#include <rsys/dynamic_array.h> +#include <rsys/mem_allocator.h> #include <math.h> +#include <string.h> +#include <ctype.h> +#include <omp.h> + +enum log_record_type { + RECORD_INVALID = BIT(0), + RECORD_UNKNOWN = BIT(1), + RECORD_UNUSED = BIT(2), + RECORD_DEFAULT = BIT(3), + RECORD_TYPES_UNDEF__ = BIT(4) +}; + +struct log_record { + enum log_record_type type; + int line_num, var_num; + struct str name; + const char* keep_line; + double default_value; + struct mem_allocator* allocator; +}; + +static FINLINE res_T +log_record_create + (struct mem_allocator* allocator, + const enum log_record_type type, + struct log_record** out_record) +{ + struct log_record* record; + ASSERT(allocator && out_record); + record = MEM_ALLOC(allocator, sizeof(*record)); + if(!record) return RES_MEM_ERR; + record->type = type; + record->line_num = -1; + record->var_num = -1; + record->keep_line = NULL; + record->default_value = INF; + str_init(allocator, &record->name); + record->allocator = allocator; + *out_record = record; + return RES_OK; +} + +static FINLINE void +log_record_release + (struct log_record* data) +{ + str_release(&data->name); + MEM_RM(data->allocator, data); +} + +#define DARRAY_NAME logs +#define DARRAY_DATA struct log_record* +#include <rsys/dynamic_array.h> void check_green_table_variables_use @@ -32,51 +90,54 @@ check_green_table_variables_use ASSERT(green); ASSERT(!green->references_checked); /* Fix double call in caller */ - /* Clear previous data */ - FOR_EACH(i, 0, 1 + green->counts.desc_count) { - green->table[i].end_references_count = 0; - green->table[i].other_references_weight = 0; - } FOR_EACH(i, 0, green->counts.ok_count) { const struct sample* sample = green->samples + i; unsigned id = sample->header.end_id; - enum description_type type = green->descriptions[id].type; - ASSERT(!DESC_IS_H(type)); - ASSERT(id <= green->counts.desc_count); /* Ambient ID is desc_count */ - green->table[id].end_references_count++; + /* Ambient ID is desc_count */ + ASSERT(id <= green->counts.desc_count); + ASSERT(id == green->counts.desc_count + || DESC_HOLDS_T(green->descriptions[id].type)); + if(sample->header.at_initial) + green->table[id].initial_T_weight++; + else + green->table[id].imposed_T_weight++; FOR_EACH(j, 0, sample->header.pw_count) { const double w = sample->pw_weights[j]; id = sample->pw_ids[j]; ASSERT(id < green->counts.desc_count); - type = green->descriptions[id].type; - ASSERT(DESC_IS_MEDIUM(type)); - green->table[id].other_references_weight += w; + ASSERT(DESC_IS_MEDIUM(green->descriptions[id].type)); + green->table[id].other_weight += w; } FOR_EACH(j, 0, sample->header.fx_count) { const double w = sample->fx_weights[j]; id = sample->fx_ids[j]; ASSERT(id < green->counts.desc_count); - type = green->descriptions[id].type; - ASSERT(DESC_IS_F(type)); - green->table[id].other_references_weight += w; + ASSERT(DESC_IS_F(green->descriptions[id].type)); + green->table[id].other_weight += w; } } green->references_checked = 1; } -#define INSERT(Name, Val, Used) { \ +#define INSERT(Elt, Field) { \ struct variable_data vd___; \ - vd___.value = (Val); vd___.used = (Used) != 0;\ - if(!vd___.used) green->unused_variables = 1; \ - if(htable_variable_ptr_find(&green->variable_ptrs, &(Name))) \ - FATAL("Name already known"); \ - ERR(htable_variable_ptr_set(&green->variable_ptrs, &(Name), &vd___)); \ + vd___.idx = ((Elt) * sizeof(struct applied_settings_elt) \ + + offsetof(struct applied_settings_elt, Field ## _value)) / sizeof(double); \ + vd___.used = (green->table[Elt].Field ## _weight != 0); \ + vd___.unknown = green->table[Elt].Field ## _unknown; \ + if(vd___.unknown) green->unknown_variables = 1; \ + else if(!vd___.used) green->unused_variables = 1; \ + if(htable_variable_ptr_find(&green->variable_ptrs, \ + &(green->table[Elt].Field ## _name))) \ + FATAL("Name already known"); /* Should have been detected by stardis */ \ + ERR(htable_variable_ptr_set(&green->variable_ptrs, \ + &(green->table[Elt].Field ## _name), &vd___)); \ } (void)0 #define MK_VAR(Str) \ for(;;) { \ - int n = snprintf(buf, bufsz, (Str), str_cget(name));\ + size_t n = (size_t)snprintf(buf, bufsz, (Str), str_cget(name));\ if(n < bufsz) break; \ buf = MEM_REALLOC(green->allocator, buf, n + 1); \ bufsz = n + 1; \ @@ -106,64 +167,83 @@ build_green_table init_table_elt(green->allocator, green->table + i); check_green_table_variables_use(green); + FOR_EACH(i, 0, green->counts.desc_count) { desc = green->descriptions + i; name = get_description_name(desc); if(DESC_IS_T(desc->type)) { MK_VAR("%s.T"); - str_set(&green->table[i].end_name, buf); - green->table[i].end_value = desc->d.t_boundary.imposed_temperature; - green->table[i].end_defined = 1; - INSERT(green->table[i].end_name, green->table[i].end_value, - green->table[i].end_references_count); + ERR(str_set(&green->table[i].imposed_T_name, buf)); + ASSERT(desc->d.t_boundary.imposed_temperature >= 0); + green->table[i].imposed_T_value = desc->d.t_boundary.imposed_temperature; + green->table[i].imposed_T_defined = 1; + INSERT(i, imposed_T); } else if(DESC_IS_H(desc->type)) { MK_VAR("%s.T"); - str_set(&green->table[i].end_name, buf); - green->table[i].end_value = desc->d.h_boundary.imposed_temperature; - green->table[i].end_defined = 1; - INSERT(green->table[i].end_name, green->table[i].end_value, - green->table[i].end_references_count); + ERR(str_set(&green->table[i].imposed_T_name, buf)); + ASSERT(desc->d.h_boundary.imposed_temperature >= 0); + green->table[i].imposed_T_value = desc->d.h_boundary.imposed_temperature; + green->table[i].imposed_T_defined = 1; + INSERT(i, imposed_T); } else if(DESC_IS_F(desc->type)) { MK_VAR("%s.F"); - str_set(&green->table[i].other_name, buf); + ERR(str_set(&green->table[i].other_name, buf)); green->table[i].other_value = desc->d.f_boundary.imposed_flux; green->table[i].other_defined = 1; - INSERT(green->table[i].other_name, green->table[i].other_value, - green->table[i].other_references_weight); + INSERT(i, other); } else if(DESC_IS_MEDIUM(desc->type)) { - MK_VAR("%s.T"); - str_set(&green->table[i].end_name, buf); - green->table[i].end_defined = 1; - INSERT(green->table[i].end_name, green->table[i].end_value, - green->table[i].end_references_count); if(desc->type == DESC_MAT_SOLID) { - green->table[i].end_value = desc->d.solid.imposed_temperature; + MK_VAR("%s.T"); + ERR(str_set(&green->table[i].imposed_T_name, buf)); + green->table[i].imposed_T_value = desc->d.solid.imposed_temperature; + green->table[i].imposed_T_defined = 1; + if(green->table[i].imposed_T_value < 0) + green->table[i].imposed_T_unknown = 1; + INSERT(i, imposed_T); + MK_VAR("%s.Tinit"); + ERR(str_set(&green->table[i].initial_T_name, buf)); + green->table[i].initial_T_value = desc->d.solid.tinit; + green->table[i].initial_T_defined = 1; + if(green->table[i].initial_T_value < 0) + green->table[i].initial_T_unknown = 1; + INSERT(i, initial_T); MK_VAR("%s.VP"); - str_set(&green->table[i].other_name, buf); + ERR(str_set(&green->table[i].other_name, buf)); green->table[i].other_value = desc->d.solid.vpower; green->table[i].other_defined = 1; - INSERT(green->table[i].other_name, green->table[i].other_value, - green->table[i].other_references_weight); - } else { /* No VP for fluids yet */ - green->table[i].end_value = desc->d.fluid.imposed_temperature; + INSERT(i, other); + } else { + MK_VAR("%s.T"); + ERR(str_set(&green->table[i].imposed_T_name, buf)); + green->table[i].imposed_T_value = desc->d.fluid.imposed_temperature; + green->table[i].imposed_T_defined = 1; + if(green->table[i].imposed_T_value < 0) + green->table[i].imposed_T_unknown = 1; + INSERT(i, imposed_T); + MK_VAR("%s.Tinit"); + ERR(str_set(&green->table[i].initial_T_name, buf)); + green->table[i].initial_T_value = desc->d.fluid.tinit; + green->table[i].initial_T_defined = 1; + if(green->table[i].initial_T_value < 0) + green->table[i].initial_T_unknown = 1; + INSERT(i, initial_T); } } else if(desc->type == DESC_SOLID_FLUID_CONNECT) { /* No variables here */ } - else FATAL("Invalid desc type."); + else FATAL("Invalid desc type."); /* Should have been detected by stardis */ } /* Ambient ID is desc_count */ ambient_id = green->counts.desc_count; desc = green->descriptions + ambient_id; - str_set(&green->table[ambient_id].end_name, "AMBIENT"); - green->table[ambient_id].end_value = green->ambient_temp; - green->table[ambient_id].end_defined = 1; - INSERT(green->table[ambient_id].end_name, green->table[ambient_id].end_value, - green->table[ambient_id].end_references_count); + ERR(str_set(&green->table[ambient_id].imposed_T_name, "AMBIENT")); + green->table[ambient_id].imposed_T_value = green->ambient_temp; + green->table[ambient_id].imposed_T_defined = 1; + INSERT(ambient_id, imposed_T); end: MEM_RM(green->allocator, buf); @@ -175,8 +255,22 @@ error: #undef INSERT static void +applied_settings_set_defaults + (const struct green* green, + struct applied_settings_elt* settings) +{ + unsigned i; + FOR_EACH(i, 0, 1 + green->counts.desc_count) { + settings[i].imposed_T_value = green->table[i].imposed_T_value; + settings[i].initial_T_value = green->table[i].initial_T_value; + settings[i].other_value = green->table[i].other_value; + } +} + +static void green_compute_1 (const struct green* green, + const struct applied_settings_elt* settings, double* E, double* STD) { @@ -189,29 +283,36 @@ green_compute_1 FOR_EACH(i, 0, green->counts.ok_count) { const struct sample* sample = green->samples + i; unsigned id = sample->header.end_id; - enum description_type type = green->descriptions[id].type; - ASSERT(DESC_IS_T(type) || DESC_IS_H(type)); ASSERT(id <= green->counts.desc_count); /* Ambient ID is desc_count */ - ASSERT(green->table[id].end_defined); - Ti = green->table[id].end_value; + ASSERT(id == green->counts.desc_count + || DESC_IS_T(green->descriptions[id].type) + || DESC_IS_H(green->descriptions[id].type) + || DESC_IS_MEDIUM(green->descriptions[id].type)); + if(sample->header.at_initial) { + ASSERT(green->table[id].initial_T_defined + && !green->table[id].initial_T_unknown); + Ti = settings[id].initial_T_value; + } else { + ASSERT(green->table[id].imposed_T_defined + && !green->table[id].imposed_T_unknown); + Ti = settings[id].imposed_T_value; + } FOR_EACH(j, 0, sample->header.pw_count) { const double w = sample->pw_weights[j]; id = sample->pw_ids[j]; ASSERT(id < green->counts.desc_count); - type = green->descriptions[id].type; - ASSERT(DESC_IS_MEDIUM(type)); - ASSERT(green->table[id].other_defined); - Ti += w * green->table[id].other_value; + ASSERT(DESC_IS_MEDIUM(green->descriptions[id].type)); + ASSERT(green->table[id].other_defined && !green->table[id].other_unknown); + Ti += w * settings[id].other_value; } FOR_EACH(j, 0, sample->header.fx_count) { const double w = sample->fx_weights[j]; id = sample->fx_ids[j]; ASSERT(id < green->counts.desc_count); - type = green->descriptions[id].type; - ASSERT(DESC_IS_F(type)); - ASSERT(green->table[id].other_defined); - Ti += w * green->table[id].other_value; + ASSERT(DESC_IS_F(green->descriptions[id].type)); + ASSERT(green->table[id].other_defined && !green->table[id].other_unknown); + Ti += w * settings[id].other_value; } T += Ti; T2 += Ti * Ti; @@ -221,128 +322,268 @@ green_compute_1 *STD = (V > 0) ? sqrt(V / (double)green->counts.ok_count) : 0; } +static int +cmp_records + (void const* r1, void const* r2) +{ + ASSERT(r1 && r2); + const struct log_record* record1 = *(struct log_record**)r1; + const struct log_record* record2 = *(struct log_record**)r2; + if(record1->line_num == record2->line_num) + return record1->var_num - record2->var_num; + return record1->line_num - record2->line_num; +} + +static void +do_log + (const char* file_name, + struct green* green, + struct darray_logs* logs) +{ + size_t i; + int prev_line_num = INT_MAX; + enum log_type log_type = LOG_WARNING; + ASSERT(file_name && green && logs); + + if(darray_logs_size_get(logs) == 0) return; + + /* Sort records by #line */ + qsort(darray_logs_data_get(logs), + darray_logs_size_get(logs), + sizeof(*darray_logs_data_get(logs)), + cmp_records); + + FOR_EACH(i, 0, darray_logs_size_get(logs)) { + struct log_record* record = darray_logs_data_get(logs)[i]; + if(record->type & (RECORD_INVALID | RECORD_UNKNOWN)) { + log_type = LOG_ERROR; + break; + } + } + logger_print(green->logger, log_type, "In file '%s':\n", file_name); + FOR_EACH(i, 0, darray_logs_size_get(logs)) { + struct log_record* record = darray_logs_data_get(logs)[i]; + switch (record->type) { + case RECORD_INVALID: + if(record->line_num != prev_line_num) { + logger_print(green->logger, LOG_ERROR, + "In line #%d: '%s':\n", + record->line_num, record->keep_line); + logger_print(green->logger, LOG_ERROR, + (str_is_empty(&record->name) + ? "Invalid data (missing name)\n" : "Invalid data (missing value)\n")); + } else + logger_print(green->logger, LOG_ERROR, + (str_is_empty(&record->name) + ? "Invalid data (missing name)\n" : "Invalid data (missing value)\n")); + break; + case RECORD_UNKNOWN: + if(record->line_num != prev_line_num) { + logger_print(green->logger, LOG_ERROR, + "In line #%d: '%s':\n", + record->line_num, record->keep_line); + logger_print(green->logger, LOG_ERROR, + "Unknown variable name: '%s'\n", + str_cget(&record->name)); + } else + logger_print(green->logger, LOG_ERROR, + "\tUnknown variable name: '%s'\n", + str_cget(&record->name)); + break; + case RECORD_UNUSED: + if(record->line_num != prev_line_num) { + logger_print(green->logger, LOG_WARNING, + "In line #%d: '%s':\n", + record->line_num, record->keep_line); + logger_print(green->logger, LOG_WARNING, + "Attempt to change unused variable '%s'.\n", + str_cget(&record->name)); + } else + logger_print(green->logger, LOG_WARNING, + "\tAttempt to change unused variable '%s'.\n", + str_cget(&record->name)); + break; + case RECORD_DEFAULT: + if(record->line_num != prev_line_num) { + logger_print(green->logger, LOG_WARNING, + "In line #%d: '%s':\n", + record->line_num, record->keep_line); + logger_print(green->logger, LOG_WARNING, + "Change variable '%s' to its default value %g.\n", + str_cget(&record->name), record->default_value); + } else + logger_print(green->logger, LOG_WARNING, + "Change variable '%s' to its default value %g.\n", + str_cget(&record->name), record->default_value); + break; + default: + FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); + } + prev_line_num = record->line_num; + } +} + static res_T parse_line (const char* file_name, - char* line, - struct green* green) + const int idx, + struct green* green, + struct applied_settings_elt* settings, + struct darray_logs* logs) { res_T res = RES_OK; - struct str keep; - int name_count = 0; + int name_count; struct str name; - char* tk = NULL, * tok_ctx = NULL; + char* tk_name = NULL; + char* tk_value = NULL; + char* tok_ctx = NULL; + const struct str* keep_line; + struct str line; + ASSERT(file_name && green && settings && logs && idx >= 0); - ASSERT(file_name && line && green); - - str_init(green->allocator, &keep); + keep_line = darray_str_cdata_get(&green->settings) + idx; + str_init(green->allocator, &line); str_init(green->allocator, &name); - ERR(str_set(&keep, line)); + ERR(str_set(&line, str_cget(keep_line))); /* At least one name=value, no name without value */ - for(;;) { + for(name_count = 0; ; name_count++) { struct variable_data* vd; - tk = strtok_r(name_count ? NULL : line, "=", &tok_ctx); - if(tk) { + struct log_record* record = NULL; + double prev; + + if(res != RES_OK) goto error; + + tk_name = strtok_r(name_count ? NULL : str_get(&line), "=", &tok_ctx); + if(tk_name) { char* c; - c = tk + strlen(tk) - 1; - while(c >= tk && isspace(*tk)) tk++; - while(c >= tk && isspace(*c)) { + c = tk_name + strlen(tk_name) - 1; + while(c >= tk_name && isspace(*tk_name)) tk_name++; + while(c >= tk_name && isspace(*c)) { *c = '\0'; c--; } - if(c < tk) tk = NULL; + if(c < tk_name) tk_name = NULL; } - if(!tk) { - if(name_count == 0) { - /* At least 1 name */ - logger_print(green->logger, LOG_ERROR, - "Invalid data (missing name)\n"); - res = RES_BAD_ARG; - goto error; - } - else break; + tk_value = strtok_r(NULL, " \t", &tok_ctx); + if((tk_name == NULL) != (tk_value == NULL)) { + /* '<name> = <value>' or '' */ + ERR(log_record_create(green->allocator, RECORD_INVALID, &record)); + if(tk_name) { ERR(str_set(&record->name, tk_name)); } + res = RES_BAD_ARG; + goto push_record; } - str_set(&name, tk); - CHK_TOK(strtok_r(NULL, " \t", &tok_ctx), "value"); + if(!tk_name) break; /* End of data */ + /* Check name validity */ + ERR(str_set(&name, tk_name)); vd = htable_variable_ptr_find(&green->variable_ptrs, &name); - if(!vd || !vd->used) { - /* Name should exist */ - if(!vd) { - logger_print(green->logger, LOG_ERROR, - "Invalid data (unknown name: '%s')", - str_cget(&name)); - res = RES_BAD_ARG; - goto error; - } - logger_print(green->logger, LOG_WARNING, - "Attempt to change unused variable '%s'\n", str_cget(&name)); - logger_print(green->logger, LOG_WARNING, "In file '%s':\n", file_name); - logger_print(green->logger, LOG_WARNING, "%s\n", str_cget(&keep)); + if(!vd) { + ERR(log_record_create(green->allocator, RECORD_UNKNOWN, &record)); + ERR(str_set(&record->name, tk_name)); + res = RES_BAD_ARG; + goto push_record; + } + if(!vd->used) { + ERR(log_record_create(green->allocator, RECORD_UNUSED, &record)); + ERR(str_set(&record->name, tk_name)); + goto push_record; + } + /* Variable exists and is used in Green function: check if really changed */ + prev = ((double*)settings)[vd->idx]; + ERR(cstr_to_double(tk_value, ((double*)settings) + vd->idx)); + if(prev == ((double*)settings)[vd->idx]) { + ERR(log_record_create(green->allocator, RECORD_DEFAULT, &record)); + ERR(str_set(&record->name, tk_name)); + record->default_value = prev; + goto push_record; + } + continue; +push_record: + #pragma omp critical + { + res_T tmp_res; + ASSERT(record && record->type != RECORD_TYPES_UNDEF__); + record->line_num = idx; + record->var_num = name_count; + record->keep_line = str_cget(keep_line); + tmp_res = darray_logs_push_back(logs, &record); + if(res == RES_OK) res = tmp_res; } - ERR(cstr_to_double(tk, &vd->value)); - name_count++; } end: - str_release(&keep); + str_release(&line); str_release(&name); return res; error: - logger_print(green->logger, LOG_ERROR, - "Invalid line in file '%s':\n", file_name); - logger_print(green->logger, LOG_ERROR, "%s\n", str_cget(&keep)); goto end; } res_T green_compute (struct green* green, - const char* in_name, - const int mode, - FILE* out_stream) + const char* in_name) { res_T res = RES_OK; - struct txtrdr* txtrdr = NULL; - FILE* stream = NULL; - struct str keep; - double E, STD; + size_t sz, n; + int i; + struct applied_settings_elt** settings = NULL; + struct darray_logs logs; ASSERT(green && in_name); + sz = darray_str_size_get(&green->settings); + ASSERT(sz < INT_MAX); - str_init(green->allocator, &keep); - stream = fopen(in_name, "r"); - if(!stream) { - logger_print(green->logger, LOG_ERROR, - "Cannot open model file '%s'\n", - in_name); - res = RES_IO_ERR; + settings = MEM_CALLOC(green->allocator, green->nthreads, sizeof(*settings)); + if(settings == NULL) { + res = RES_MEM_ERR; goto error; } - txtrdr_stream(green->allocator, stream, in_name, '#', &txtrdr); - for(;;) { - char* line; - ERR(txtrdr_read_line(txtrdr)); - line = txtrdr_get_line(txtrdr); - if(!line) break; - if(mode & MODE_EXTENTED_RESULTS) str_set(&keep, line); + darray_logs_init(green->allocator, &logs); + + omp_set_num_threads((int)green->nthreads); + #pragma omp parallel for schedule(static) + for(i = 0; i < (int)sz; i++) { + struct result* result = darray_result_data_get(&green->results) + i; + res_T tmp_res = RES_OK; + int t = omp_get_thread_num(); + + if(res != RES_OK) continue; + + if(settings[t] == NULL) { + /* desc_count + 1 for AMBIENT */ + settings[t] = MEM_CALLOC(green->allocator, 1 + green->counts.desc_count, + sizeof(**settings)); + if(settings[t] == NULL) { + res = RES_MEM_ERR; + continue; + } + } + /* Apply settings */ - ERR(parse_line(in_name, line, green)); + applied_settings_set_defaults(green, settings[t]); + tmp_res = parse_line(in_name, i, green, settings[t], &logs); + if(tmp_res != RES_OK) { + res = tmp_res; + continue; + } /* Compute */ - green_compute_1(green, &E, &STD); - /* Print results */ - if(mode & MODE_EXTENTED_RESULTS) - fprintf(out_stream, "%g +/- %g ; %s\n", E, STD, str_cget(&keep)); - else fprintf(out_stream, "%g %g\n", E, STD); - } - txtrdr_ref_put(txtrdr); - txtrdr = NULL; + green_compute_1(green, settings[t], &result->E, &result->STD); + } /* Implicit barrier */ + if(res != RES_OK) goto error; exit: - str_release(&keep); - if(stream) fclose(stream); - if(txtrdr) txtrdr_ref_put(txtrdr); + do_log(in_name, green, &logs); + if(settings) { + FOR_EACH(n, 0, green->nthreads) MEM_RM(green->allocator, settings[n]); + MEM_RM(green->allocator, settings); + } + FOR_EACH(n, 0, darray_logs_size_get(&logs)) { + struct log_record* record = darray_logs_data_get(&logs)[n]; + log_record_release(record); + } + darray_logs_release(&logs); return res; error: goto exit; diff --git a/src/green-compute.h b/src/green-compute.h @@ -33,8 +33,6 @@ build_green_table res_T green_compute (struct green* green, - const char* in_name, - const int mode, - FILE* out_stream); + const char* in_name); #endif /* GREEN_COMPUTE_H */ \ No newline at end of file diff --git a/src/green-input.c b/src/green-input.c @@ -20,6 +20,7 @@ #include <rsys/str.h> #include <rsys/logger.h> #include <rsys/mem_allocator.h> +#include <rsys/text_reader.h> #include <stdlib.h> @@ -53,7 +54,7 @@ error: } res_T -read_green +read_green_function (struct green* green, FILE* stream) { @@ -106,6 +107,9 @@ read_green FR(&green->ambient_temp, 1); FR(&green->ref_temp, 1); + /* Read time range */ + FR(&green->time_range, 2); + /* Read samples*/ green->samples = MEM_CALLOC(green->allocator, green->counts.ok_count, sizeof(*green->samples)); @@ -125,3 +129,46 @@ end: error: goto end; } + +res_T +green_read_settings + (struct green* green, + const char* in_name) +{ + res_T res = RES_OK; + struct txtrdr* txtrdr = NULL; + FILE* stream = NULL; + + ASSERT(green && in_name); + + stream = fopen(in_name, "r"); + if(!stream) { + logger_print(green->logger, LOG_ERROR, + "Cannot open model file '%s'\n", + in_name); + res = RES_IO_ERR; + goto error; + } + txtrdr_stream(green->allocator, stream, in_name, '#', &txtrdr); + for(;;) { + char* line; + size_t sz; + ERR(txtrdr_read_line(txtrdr)); + line = txtrdr_get_line(txtrdr); + if(!line) break; + sz = darray_str_size_get(&green->settings); + ERR(darray_str_resize(&green->settings, 1 + sz)); + ERR(str_set(darray_str_data_get(&green->settings) + sz, line)); + } + ERR(darray_result_resize(&green->results, + darray_str_size_get(&green->settings))); + txtrdr_ref_put(txtrdr); + txtrdr = NULL; + +exit: + if(stream) fclose(stream); + if(txtrdr) txtrdr_ref_put(txtrdr); + return res; +error: + goto exit; +} diff --git a/src/green-main.c b/src/green-main.c @@ -23,6 +23,7 @@ #include <rsys/logger.h> #include <stdlib.h> +#include <omp.h> int main @@ -31,8 +32,7 @@ main { int err = EXIT_SUCCESS; res_T res = RES_OK; - int logger_initialized = 0, allocator_initialized = 0, - green_initialized = 0; + int logger_initialized = 0, green_initialized = 0, allocator_initialized = 0; struct mem_allocator allocator; struct logger logger; struct green green; @@ -69,20 +69,33 @@ main if(args.verbose < 3) logger_set_stream(&logger, LOG_OUTPUT, NULL, NULL); - if(args.green_filename) { - stream = fopen(args.green_filename, "rb"); - if(!stream) { - logger_print(&logger, LOG_ERROR, - "Cannot open model file '%s'\n", args.green_filename); - res = RES_IO_ERR; - goto error; + green_init(&allocator, &logger, args.nthreads, &green); + green_initialized = 1; + #pragma omp parallel sections num_threads(args.nthreads) + { + /* If there are some settings to apply read the 2 files at the same time*/ + #pragma omp section + if(args.green_filename) { + stream = fopen(args.green_filename, "rb"); + if(!stream) { + logger_print(&logger, LOG_ERROR, + "Cannot open model file '%s'\n", args.green_filename); + res = RES_IO_ERR; + } else { + res_T tmp_err; + tmp_err = read_green_function(&green, stream); + fclose(stream); + if(tmp_err != RES_OK) res = tmp_err; + } } - green_init(&allocator, &logger, &green); - green_initialized = 1; - ERR(read_green(&green, stream)); - fclose(stream); stream = NULL; - } - + #pragma omp section + if(args.mode & MODE_APPLY_GREEN) { + res_T tmp_res; + tmp_res = green_read_settings(&green, args.command_filename); + if(tmp_res != RES_OK) res = tmp_res; + } + } /* Implicit barrier */ + if(res != RES_OK) goto error; if(args.mode & MODE_HTML_SUMMARY) { ASSERT(args.info_filename); stream = fopen(args.info_filename, "w"); @@ -97,12 +110,24 @@ main } if(args.mode & MODE_APPLY_GREEN) { - ERR(green_compute(&green, args.command_filename, args.mode, stdout)); + ERR(green_compute(&green, args.command_filename)); + green_print_result(&green, args.mode, stdout); } exit: if(green_initialized) green_release(&green); + if(logger_initialized) logger_release(&logger); if(stream) fclose(stream); + if(allocator_initialized) { + if(MEM_ALLOCATED_SIZE(&allocator) != 0) { + char dump[4096] = { '\0' }; + MEM_DUMP(&allocator, dump, sizeof(dump)); + fprintf(stderr, "%s\n", dump); + fprintf(stderr, "\nMemory leaks: %zu Bytes\n", + MEM_ALLOCATED_SIZE(&allocator)); + } + mem_shutdown_proxy_allocator(&allocator); + } return err; error: err = EXIT_FAILURE; diff --git a/src/green-output.c b/src/green-output.c @@ -17,22 +17,30 @@ #include <rsys/str.h> #include <rsys/mem_allocator.h> +#include "green-output.h" #include "green-types.h" #include "green-version.h" +#include <stdio.h> + #define CELL(T,Val) \ fprintf(stream, " <td>%" #T "</td>\n", (Val)) -#define MCELL(T,Used,Name,Val) { \ - if(Used) \ - fprintf(stream, " <td><u><b>%s = %" #T "</b></u></td>\n", (Name), (Val)); \ - else fprintf(stream, " <td>%s = %" #T "</td>\n", (Name), (Val)); \ +#define VAR_CELL(Elt, Field) { \ + const char* name___ = str_cget(&(green->table[Elt].Field ## _name)); \ + if((green->table[Elt]). Field ## _unknown) { \ + fprintf(stream, " <td>%s = Unknown</td>\n", name___); \ + } else if(green->table[Elt].Field ## _defined \ + && green->table[Elt].Field ## _weight > 0) \ + { \ + fprintf(stream, " <td><u><b>%s = %g</b></u></td>\n", \ + name___, green->table[Elt].Field ## _value); \ + } else { \ + fprintf(stream, " <td>%s = %g</td>\n", \ + name___, green->table[Elt].Field ## _value); \ + } \ } (void)0 -#define MCELLif(T,Used,Name,Val) \ - if((Val) != 0) { MCELL(T,(Used),(Name),(Val)); } \ - else { CELL(T,(Val)); } (void)0 - void print_version (FILE* stream) @@ -65,19 +73,21 @@ short_help name); fprintf(stream, "\n -a <FILE>\n"); - fprintf(stream, " Apply a Green function using the variable settings read from file.\n"); + fprintf(stream, " Apply a Green function using the variable settings " + "read from a file.\n"); fprintf(stream, "\n -e\n"); fprintf(stream, " Use extended format to output Monte-Carlo results.\n"); fprintf(stream, "\n -g <FILE>\n"); - fprintf(stream, " Read a Green function from file.\n"); + fprintf(stream, " Read a Green function from a file.\n"); fprintf(stream, "\n -h\n"); fprintf(stream, " Print this help and exit.\n"); fprintf(stream, "\n -s <FILE>\n"); - fprintf(stream, " Create a summary of a Green function and write it to file.\n"); + fprintf(stream, " Create a summary of a Green function and write it to " + "a file.\n"); fprintf(stream, "\n -t NUM_OF_THREADS\n"); fprintf(stream, " Hint on the number of threads.\n"); @@ -90,6 +100,26 @@ short_help } void +green_print_result + (struct green* green, + const int mode, + FILE* out_stream) +{ + size_t i, sz; + + ASSERT(green && out_stream); + sz = darray_str_size_get(&green->settings); + + for(i = 0; i < sz; i++) { + struct result* result = darray_result_data_get(&green->results) + i; + const char* line = str_cget(darray_str_data_get(&green->settings) + i); + if(mode & MODE_EXTENTED_RESULTS) + fprintf(out_stream, "%g +/- %g ; %s\n", result->E, result->STD, line); + else fprintf(out_stream, "%g %g\n", result->E, result->STD); + } +} + +void dump_green_info (struct green* green, FILE* stream) @@ -127,7 +157,7 @@ dump_green_info fprintf(stream, "<h2>List of variables</h2>\n"); - fprintf(stream, "<h3>Variable used in the Green function</h3>\n"); + fprintf(stream, "<h3>Variables used in the Green function</h3>\n"); fprintf(stream, "<p>These variable names are used in the following formula. " "Using the syntax NAME=value in a settings file, their values are " @@ -137,34 +167,83 @@ dump_green_info fst = 1; FOR_EACH(i, 0, green->counts.desc_count + 1) { struct table_elt* elt = green->table + i; - if(elt->end_defined && elt->end_references_count) { - if(!fst) fprintf(stream, ", "); fst = 0; - fprintf(stream, "%s", str_cget(&elt->end_name)); + if(elt->imposed_T_defined && elt->imposed_T_weight > 0) { + if(!fst) fprintf(stream, ", "); + fst = 0; + fprintf(stream, "%s", str_cget(&elt->imposed_T_name)); + } + if(elt->initial_T_defined && elt->initial_T_weight > 0) { + if(!fst) fprintf(stream, ", "); + fst = 0; + fprintf(stream, "%s", str_cget(&elt->initial_T_name)); } - if(elt->other_defined && elt->other_references_weight) { - if(!fst) fprintf(stream, ", "); fst = 0; + if(elt->other_defined && elt->other_weight) { + if(!fst) fprintf(stream, ", "); + fst = 0; fprintf(stream, "%s", str_cget(&elt->other_name)); } } if(green->unused_variables) { fprintf(stream, - "<h3>Variable not used in the Green function</h3>\n"); + "<h3>Unused variables in the Green function</h3>\n"); fprintf(stream, "<p>These variable names are not used in the following " - "formula. Changing their values in a settings file has no effect on " - "the applied Green function results. They are listed NAME = value " - "in the tables below.</p>\n"); + "formula, just because they where not sampled. As a consequence, " + "changing their values in a settings file has no effect on the applied " + "Green function results. They are listed NAME = value in the tables " + "below.</p>\n"); + + fst = 1; + FOR_EACH(i, 0, green->counts.desc_count + 1) { + struct table_elt* elt = green->table + i; + if(elt->imposed_T_defined + && !elt->imposed_T_unknown && elt->imposed_T_weight == 0) { + if(!fst) fprintf(stream, ", "); + fst = 0; + fprintf(stream, "%s", str_cget(&elt->imposed_T_name)); + } + if(elt->initial_T_defined + && !elt->initial_T_unknown && elt->initial_T_weight == 0) { + if(!fst) fprintf(stream, ", "); + fst = 0; + fprintf(stream, "%s", str_cget(&elt->initial_T_name)); + } + if(elt->other_defined + && !elt->other_unknown && !elt->other_weight) { + if(!fst) fprintf(stream, ", "); + fst = 0; + fprintf(stream, "%s", str_cget(&elt->other_name)); + } + } + } + + if(green->unknown_variables) { + fprintf(stream, + "<h3>Unknown variables in the Green function</h3>\n"); + + fprintf(stream, "<p>These names are not true variable names because their " + "values where defined as <i>unknown</i> in the system, meaning they " + "required to be solved. Attempting to change their values in a settings " + "file is an error. They are listed NAME = Unknown in the tables below." + "</p>\n"); fst = 1; FOR_EACH(i, 0, green->counts.desc_count + 1) { struct table_elt* elt = green->table + i; - if(elt->end_defined && !elt->end_references_count) { - if(!fst) fprintf(stream, ", "); fst = 0; - fprintf(stream, "%s", str_cget(&elt->end_name)); + if(elt->imposed_T_unknown) { + if(!fst) fprintf(stream, ", "); + fst = 0; + fprintf(stream, "%s", str_cget(&elt->imposed_T_name)); + } + if(elt->initial_T_unknown) { + if(!fst) fprintf(stream, ", "); + fst = 0; + fprintf(stream, "%s", str_cget(&elt->initial_T_name)); } - if(elt->other_defined && !elt->other_references_weight) { - if(!fst) fprintf(stream, ", "); fst = 0; + if(elt->other_defined && !elt->other_weight) { + if(!fst) fprintf(stream, ", "); + fst = 0; fprintf(stream, "%s", str_cget(&elt->other_name)); } } @@ -172,47 +251,57 @@ dump_green_info fprintf(stream, "<h2>Formula of the Monte-Carlo estimate</h2>\n"); - fprintf(stream, "<p>The Monte-Carlo estimate of the Green function of the " - "system is as follows:</p>\n"); + if(green->time_range[0] == green->time_range[1]) + fprintf(stream, "<p>The Monte-Carlo estimate of the Green function of the " + "system at t=%g is as follows:</p>\n", + green->time_range[0]); + else + fprintf(stream, "<p>The Monte-Carlo estimate of the Green function of the " + "system with t in [%g %g] is as follows:</p>\n", + SPLIT2(green->time_range)); /* Print result */ fst = 1; FOR_EACH(i, 0, 1 + green->counts.desc_count) { - if(green->table[i].end_references_count) { + if(green->table[i].imposed_T_weight > 0) { + double k; + CHK(green->table[i].imposed_T_defined + && green->table[i].imposed_T_value >= 0); + if(fst) fprintf(stream, "<p>E[T] = "); + else fprintf(stream, " + "); + fst = 0; + k = (double)green->table[i].imposed_T_weight + / (double)green->counts.ok_count; + t += k * green->table[i].imposed_T_value; + fprintf(stream, "%g * <b>%s</b>", + k, str_cget(&green->table[i].imposed_T_name)); + } + if(green->table[i].initial_T_weight > 0) { double k; - ASSERT(green->table[i].end_defined); + CHK(green->table[i].initial_T_defined + && green->table[i].initial_T_value >= 0); if(fst) fprintf(stream, "<p>E[T] = "); else fprintf(stream, " + "); fst = 0; - k = (double)green->table[i].end_references_count + k = (double)green->table[i].initial_T_weight / (double)green->counts.ok_count; - t += k * green->table[i].end_value; - fprintf(stream, "%g * <b>%s</b>", k, str_cget(&green->table[i].end_name)); + t += k * green->table[i].initial_T_value; + fprintf(stream, "%g * <b>%s</b>", + k, str_cget(&green->table[i].initial_T_name)); } } ASSERT(!fst); FOR_EACH(i, 0, green->counts.desc_count) { - if(green->table[i].other_references_weight) { + if(green->table[i].other_weight) { double k; - ASSERT(green->table[i].other_defined); - k = (double)green->table[i].other_references_weight + CHK(green->table[i].other_defined); + k = (double)green->table[i].other_weight / (double)green->counts.ok_count; t += k * green->table[i].other_value; - fprintf(stream, " + %g * <b>%s</b>", k, str_cget(&green->table[i].other_name)); + fprintf(stream, " + %g * <b>%s</b>", + k, str_cget(&green->table[i].other_name)); } } - if(green->table[green->counts.desc_count].end_references_count) { - double ww = 0, k; - /* Some paths end here */ - if(fst) fprintf(stream, "<p>E(T) = "); - else fprintf(stream, " + "); - fst = 0; - ww = green->ambient_temp; - k = (double)green->table[green->counts.desc_count].end_references_count - / (double)green->counts.ok_count; - t += ww * k; - fprintf(stream, "%g * <b>Ambient</b>", k); - } fprintf(stream, " = %g</p>", t); /* Counts table */ @@ -254,7 +343,8 @@ dump_green_info fprintf(stream, " <th>Rho</th>\n"); fprintf(stream, " <th>Cp</th>\n"); fprintf(stream, " <th>Volumic Power</th>\n"); - fprintf(stream, " <th>Temperature</th>\n"); + fprintf(stream, " <th>Imposed temperature</th>\n"); + fprintf(stream, " <th>Initial temperature</th>\n"); fprintf(stream, "</tr>\n"); } sl = &desc->d.solid; @@ -263,15 +353,9 @@ dump_green_info CELL(g, sl->lambda); CELL(g, sl->rho); CELL(g, sl->cp); - ASSERT(green->table[i].other_defined); - MCELLif(g, green->table[i].other_references_weight, - str_cget(&green->table[i].other_name), sl->vpower); - if(sl->imposed_temperature >= 0) { - ASSERT(green->table[i].end_defined); - MCELL(g, green->table[i].end_references_count, - str_cget(&green->table[i].end_name), sl->imposed_temperature); - } - else CELL(s, "Unknown"); + VAR_CELL(i, other); + VAR_CELL(i, imposed_T); + VAR_CELL(i, initial_T); fprintf(stream, "</tr>\n"); local_count++; } @@ -290,7 +374,8 @@ dump_green_info fprintf(stream, " <th>Name</th>\n"); fprintf(stream, " <th>Rho</th>\n"); fprintf(stream, " <th>Cp</th>\n"); - fprintf(stream, " <th>Temperature</th>\n"); + fprintf(stream, " <th>Imposed temperature</th>\n"); + fprintf(stream, " <th>Initial temperature</th>\n"); fprintf(stream, "</tr>\n"); } fl = &desc->d.fluid; @@ -298,12 +383,8 @@ dump_green_info CELL(s, str_cget(&fl->name)); CELL(g, fl->rho); CELL(g, fl->cp); - if(fl->imposed_temperature >= 0) { - ASSERT(green->table[i].end_defined); - MCELL(g, green->table[i].end_references_count, - str_cget(&green->table[i].end_name), fl->imposed_temperature); - } - else CELL(s, "Unknown"); + VAR_CELL(i, imposed_T); + VAR_CELL(i, initial_T); fprintf(stream, "</tr>\n"); local_count++; } @@ -326,9 +407,8 @@ dump_green_info bd = &desc->d.t_boundary; fprintf(stream, "<tr>\n"); CELL(s, str_cget(&bd->name)); - ASSERT(green->table[i].end_defined); - MCELL(g, green->table[i].end_references_count, - str_cget(&green->table[i].end_name), bd->imposed_temperature); + ASSERT(green->table[i].imposed_T_defined); + VAR_CELL(i, imposed_T); fprintf(stream, "</tr>\n"); local_count++; } @@ -353,9 +433,8 @@ dump_green_info bd = &desc->d.t_boundary; fprintf(stream, "<tr>\n"); CELL(s, str_cget(&bd->name)); - ASSERT(green->table[i].end_defined); - MCELL(g, green->table[i].end_references_count, - str_cget(&green->table[i].end_name), bd->imposed_temperature); + ASSERT(green->table[i].imposed_T_defined); + VAR_CELL(i, imposed_T); CELL(g, bd->emissivity); CELL(g, bd->specular_fraction); CELL(g, bd->hc); @@ -387,9 +466,8 @@ dump_green_info CELL(g, bd->emissivity); CELL(g, bd->specular_fraction); CELL(g, bd->hc); - ASSERT(green->table[i].end_defined); - MCELL(g, green->table[i].end_references_count, - str_cget(&green->table[i].end_name), bd->imposed_temperature); + ASSERT(green->table[i].imposed_T_defined); + VAR_CELL(i, imposed_T); fprintf(stream, "</tr>\n"); local_count++; } @@ -417,10 +495,8 @@ dump_green_info CELL(g, bd->emissivity); CELL(g, bd->specular_fraction); CELL(g, bd->hc); - ASSERT(green->table[i].end_defined); - ASSERT(green->table[i].end_defined); - MCELL(g, green->table[i].end_references_count, - str_cget(&green->table[i].end_name), bd->imposed_temperature); + ASSERT(green->table[i].imposed_T_defined); + VAR_CELL(i, imposed_T); fprintf(stream, "</tr>\n"); local_count++; } @@ -444,8 +520,7 @@ dump_green_info fprintf(stream, "<tr>\n"); CELL(s, str_cget(&bd->name)); ASSERT(green->table[i].other_defined); - MCELL(g, green->table[i].other_references_weight, - str_cget(&green->table[i].other_name), bd->imposed_flux); + VAR_CELL(i, other); fprintf(stream, "</tr>\n"); local_count++; } @@ -460,10 +535,8 @@ dump_green_info fprintf(stream, "</tr>\n"); fprintf(stream, "<tr>\n"); CELL(s, "Ambient"); - ASSERT(green->table[green->counts.desc_count].end_defined); - MCELL(g, green->table[i].end_references_count, - str_cget(&green->table[green->counts.desc_count].end_name), - green->ambient_temp); + ASSERT(green->table[green->counts.desc_count].imposed_T_defined); + VAR_CELL(green->counts.desc_count, imposed_T); fprintf(stream, "</tr>\n"); fprintf(stream, "<tr>\n"); CELL(s, "Linearization"); @@ -477,5 +550,4 @@ dump_green_info } #undef CELL -#undef MCELL -#undef MCELLif -\ No newline at end of file +#undef VAR_CELL +\ No newline at end of file diff --git a/src/green-output.h b/src/green-output.h @@ -20,6 +20,8 @@ #include <stdio.h> +struct green; + void print_version (FILE* stream); @@ -30,6 +32,12 @@ short_help FILE* stream); void +green_print_result + (struct green* green, + const int mode, + FILE* out_stream); + +void dump_green_info (struct green* green, FILE* stream); diff --git a/src/green-types.h b/src/green-types.h @@ -19,8 +19,12 @@ #include <rsys/str.h> #include <rsys/mem_allocator.h> #include <rsys/hash_table.h> +#include <rsys/dynamic_array.h> +#include <rsys/dynamic_array_char.h> +#include <rsys/dynamic_array_str.h> #include <string.h> +#include <omp.h> /* Utility macros */ #define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; else (void)0 @@ -118,8 +122,8 @@ enum green_mode { */ struct sample_header { unsigned end_id; - unsigned pw_count; - unsigned fx_count; + unsigned pw_count, fx_count; + char at_initial; }; struct sample { @@ -130,7 +134,7 @@ struct sample { double* fx_weights; }; -static res_T +static INLINE res_T alloc_sample_buffers (struct mem_allocator* alloc, struct sample* sample) @@ -176,17 +180,22 @@ release_sample } /* - * Table used to compute green + * Types used to compute green */ -struct table_elt { - struct str end_name; - struct str other_name; - double end_value; +struct applied_settings_elt { + double imposed_T_value, initial_T_value; double other_value; - int end_defined, other_defined; - int end_references_count; - double other_references_weight; +}; + +/* other is used both for power and flux, as no description can have both */ +struct table_elt { + struct str imposed_T_name, initial_T_name, other_name; + double imposed_T_value, initial_T_value, other_value; + int imposed_T_defined, initial_T_defined, other_defined; + int imposed_T_unknown, initial_T_unknown, other_unknown; + unsigned imposed_T_weight, initial_T_weight; + double other_weight; }; static INLINE void @@ -195,14 +204,21 @@ init_table_elt struct table_elt* elt) { ASSERT(alloc && elt); - str_init(alloc, &elt->end_name); + str_init(alloc, &elt->imposed_T_name); + str_init(alloc, &elt->initial_T_name); str_init(alloc, &elt->other_name); - elt->end_value = 0; + elt->imposed_T_value = 0; + elt->initial_T_value = 0; elt->other_value = 0; - elt->end_defined = 0; + elt->imposed_T_defined = 0; + elt->initial_T_defined = 0; elt->other_defined = 0; - elt->end_references_count = 0; - elt->other_references_weight = 0; + elt->imposed_T_unknown = 0; + elt->initial_T_unknown = 0; + elt->other_unknown = 0; + elt->imposed_T_weight = 0; + elt->initial_T_weight = 0; + elt->other_weight = 0; } static INLINE void @@ -210,13 +226,15 @@ release_table_elt (struct table_elt* elt) { ASSERT(elt); - str_release(&elt->end_name); + str_release(&elt->imposed_T_name); + str_release(&elt->initial_T_name); str_release(&elt->other_name); } struct variable_data { - double value; + size_t idx; int used; + int unknown; }; #define HTABLE_NAME variable_ptr @@ -230,6 +248,14 @@ struct variable_data { #define HTABLE_KEY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release #include <rsys/hash_table.h> +struct result { + double E, STD; +}; + +#define DARRAY_NAME result +#define DARRAY_DATA struct result +#include <rsys/dynamic_array.h> + /* * Main type to store binary file content */ @@ -240,16 +266,21 @@ struct green { char* names_pool; struct description* descriptions; double ambient_temp, ref_temp; + double time_range[2]; struct table_elt* table; struct sample* samples; - int references_checked, unused_variables; + int references_checked, unused_variables, unknown_variables; + unsigned nthreads; struct htable_variable_ptr variable_ptrs; + struct darray_str settings; + struct darray_result results; }; static INLINE void green_init (struct mem_allocator* alloc, struct logger* logger, + const unsigned nthreads, struct green* green) { ASSERT(alloc && green); @@ -264,7 +295,11 @@ green_init green->ref_temp = 0; green->references_checked = 0; green->unused_variables = 0; + green->unknown_variables = 0; + green->nthreads = MMIN(nthreads, (unsigned)omp_get_num_procs()); htable_variable_ptr_init(alloc, &green->variable_ptrs); + darray_str_init(alloc, &green->settings); + darray_result_init(alloc, &green->results); } static INLINE void @@ -279,18 +314,25 @@ green_release FOR_EACH(i, 0, green->counts.ok_count) release_sample(green->allocator, green->samples + i); FOR_EACH(i, 0, 1 + green->counts.desc_count) - release_table_elt(&green->table[i]); + if(&green->table[i]) release_table_elt(&green->table[i]); MEM_RM(green->allocator, green->table); MEM_RM(green->allocator, green->samples); green->allocator = NULL; htable_variable_ptr_release(&green->variable_ptrs); + darray_str_release(&green->settings); + darray_result_release(&green->results); } res_T -read_green +read_green_function (struct green* green, FILE* stream); +res_T +green_read_settings + (struct green* green, + const char* in_name); + /* * Different types of descriptions read from the binary file */ @@ -315,50 +357,62 @@ enum description_type { ((D) == DESC_BOUND_T_FOR_SOLID || (D) == DESC_BOUND_T_FOR_FLUID) #define DESC_IS_F(D) \ ((D) == DESC_BOUND_F_FOR_SOLID) +#define DESC_IS_SF(D) \ + ((D) == DESC_SOLID_FLUID_CONNECT) +#define DESC_HOLDS_T(D) \ + (DESC_IS_MEDIUM(D) || DESC_IS_H(D) || DESC_IS_T(D)) struct mat_fluid { struct str name; - unsigned fluid_id; - double rho; - double cp; + double rho; /* Volumic mass */ + double cp; /* Calorific capacity */ double tinit; double imposed_temperature; + double t0; /* End time of tinit */ + int is_outside; /* the fluid is used for a boundary */ + int is_green; /* green computation nothing to do with fluid itself) */ + unsigned desc_id; /* id of the boundary; meaningful if is_outside */ + unsigned fluid_id; }; struct mat_solid { struct str name; - unsigned solid_id; - double lambda; - double rho; - double cp; - double delta; - double tinit; - double imposed_temperature; + double lambda; /* Conductivity */ + double rho; /* Volumic mass */ + double cp; /* Calorific capacity */ + double delta; /* Numerical parameter */ + double tinit; /* Initial temperature */ + double imposed_temperature; /* allow to impose a T; -1 if unset */ double vpower; + double t0; /* End time of tinit */ + int is_outside; /* the fluid is used for a boundary */ + int is_green; /* green computation nothing to do with fluid itself) */ + unsigned desc_id; /* id of the boundary; meaningful if is_outside */ + unsigned solid_id; }; struct h_boundary { struct str name; - unsigned mat_id; double emissivity; double specular_fraction; double hc; double imposed_temperature; + unsigned mat_id; }; struct t_boundary { struct str name; - unsigned mat_id; double emissivity; double specular_fraction; double hc; double imposed_temperature; + unsigned mat_id; }; struct f_boundary { struct str name; - unsigned mat_id; double imposed_flux; + unsigned mat_id; }; struct solid_fluid_connect { @@ -366,6 +420,7 @@ struct solid_fluid_connect { double emissivity; double specular_fraction; double hc; + unsigned connection_id; }; struct description {