sadist_lib_trilinear_profile.c (6433B)
1 /* Copyright (C) 2024 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "sadist.h" 17 18 #include <stardis/stardis-prog-properties.h> 19 20 #include <rsys/cstr.h> 21 #include <rsys/rsys.h> 22 #include <rsys/mem_allocator.h> 23 24 #include <stdarg.h> /* va_list */ 25 #include <getopt.h> 26 27 /******************************************************************************* 28 * Helper functions 29 ******************************************************************************/ 30 static void 31 log_err(const char* msg, ...) 32 { 33 va_list vargs_list; 34 ASSERT(msg); 35 36 va_start(vargs_list, msg); 37 vfprintf(stderr, msg, vargs_list); 38 va_end(vargs_list); 39 } 40 41 static void 42 print_usage(FILE* stream, const char* name) 43 { 44 fprintf(stream, 45 "usage: %s [-h] [-b lower_xyz,upper_xyz]\n" 46 " [-t max_Tx,max_Ty,max_Tz]\n", 47 name); 48 } 49 50 static res_T 51 parse_spatial_range(struct sadist_trilinear_profile* profile, const char* str) 52 { 53 double range[2] = {0, 0}; 54 size_t len = 0; 55 res_T res = RES_OK; 56 ASSERT(profile && str); 57 58 res = cstr_to_list_double(str, ',', range, &len, 2); 59 if(res == RES_OK && len != 2) res = RES_BAD_ARG; 60 if(res != RES_OK) { 61 log_err("%s:%lu: unable to parse spatial range parameter `%s' -- %s\n", 62 __FILE__, __LINE__, str, res_to_cstr(res)); 63 goto error; 64 } 65 66 if(range[0] >= range[1]) { 67 log_err("%s:%lu: invalid spatial range [%g, %g]\n", 68 __FILE__, __LINE__, range[0], range[1]); 69 res = RES_BAD_ARG; 70 goto error; 71 } 72 73 profile->lower[0] = profile->lower[1] = profile->lower[2] = range[0]; 74 profile->upper[0] = profile->upper[1] = profile->upper[2] = range[1]; 75 76 exit: 77 return res; 78 error: 79 goto exit; 80 } 81 82 static res_T 83 parse_max_temperatures(struct sadist_trilinear_profile* profile, const char* str) 84 { 85 double abc[3] = {0, 0, 0}; 86 size_t len = 0; 87 res_T res = RES_OK; 88 ASSERT(profile && str); 89 90 res = cstr_to_list_double(str, ',', abc, &len, 3); 91 if(res == RES_OK && len != 3) res = RES_BAD_ARG; 92 if(res != RES_OK) { 93 log_err("%s:%lu: unable to parse maximum temperatures `%s' -- %s\n", 94 __FILE__, __LINE__, str, res_to_cstr(res)); 95 goto error; 96 } 97 98 if(abc[0] < 0 || abc[1] < 0 || abc[2] < 0) { 99 log_err 100 ("%s:%lu: invalid maximum temperatures (X = %g K, Y = %g K, Z = %g K)\n", 101 __FILE__, __LINE__, str, abc[0], abc[1], abc[2]); 102 res = RES_BAD_ARG; 103 goto error; 104 } 105 106 profile->a[1] = abc[0]; 107 profile->b[1] = abc[1]; 108 profile->c[1] = abc[2]; 109 110 exit: 111 return res; 112 error: 113 goto exit; 114 } 115 116 static res_T 117 parse_args 118 (const struct stardis_description_create_context* ctx, 119 struct sadist_trilinear_profile* profile, 120 int argc, 121 char* argv[]) 122 { 123 int opt; 124 res_T res = RES_OK; 125 ASSERT(ctx && profile); 126 127 optind = 1; 128 while((opt = getopt(argc, argv, "b:ht:")) != -1) { 129 switch(opt) { 130 case 'b': 131 res = parse_spatial_range(profile, optarg); 132 if(res != RES_OK) goto error; 133 break; 134 case 'h': 135 print_usage(stdout, ctx->name); 136 break; 137 case 't': 138 res = parse_max_temperatures(profile, optarg); 139 if(res != RES_OK) goto error; 140 break; 141 default: res = RES_BAD_ARG; break; 142 } 143 } 144 145 exit: 146 return res; 147 error: 148 goto exit; 149 } 150 151 /******************************************************************************* 152 * Legal notices 153 ******************************************************************************/ 154 const char* 155 get_copyright_notice(void* data) 156 { 157 (void)data; /* Avoid "unused variable" warnings */ 158 return "Copyright (C) 2024 |Méso|Star> (contact@meso-star.com)"; 159 } 160 161 const char* 162 get_license_short(void* data) 163 { 164 (void)data; /* Avoid "unused variable" warnings */ 165 return "GNU GPL version 3 or later <http://www.gnu.org/licenses/>"; 166 } 167 168 const char* 169 get_license_text(void* data) 170 { 171 (void)data; /* Avoid "unused variable" warnings */ 172 return 173 "This is free software released under the GPL v3+ license: GNU GPL\n" 174 "version 3 or later. You are welcome to redistribute it under certain\n" 175 "conditions; refer to <http://www.gnu.org/licenses/> for details."; 176 } 177 178 /******************************************************************************* 179 * Create data 180 ******************************************************************************/ 181 void* 182 stardis_create_data 183 (const struct stardis_description_create_context* ctx, 184 void* libdata, 185 size_t argc, 186 char* argv[]) 187 { 188 struct sadist_trilinear_profile* profile = NULL; 189 res_T res = RES_OK; 190 (void)libdata; 191 192 profile = mem_alloc(sizeof(*profile)); 193 if(!profile) { 194 log_err("%s:%lu: error allocating the trilinear profile.\n", 195 __FILE__, __LINE__); 196 goto error; 197 } 198 199 *profile = SADIST_TRILINEAR_PROFILE_NULL; 200 201 res = parse_args(ctx, profile, (int)argc, argv); 202 if(res != RES_OK) goto error; 203 204 exit: 205 return profile; 206 error: 207 if(profile) { 208 mem_rm(profile); 209 profile = NULL; 210 } 211 goto exit; 212 } 213 214 void 215 stardis_release_data(void* data) 216 { 217 ASSERT(data); 218 mem_rm(data); 219 } 220 221 /******************************************************************************* 222 * Boundary condition 223 ******************************************************************************/ 224 double 225 stardis_boundary_temperature 226 (const struct stardis_interface_fragment* frag, 227 void* data) 228 { 229 ASSERT(frag && data); 230 return sadist_trilinear_profile_temperature(data, frag->P); 231 } 232 233 double* 234 stardis_t_range(void* data, double range[2]) 235 { 236 struct sadist_trilinear_profile* profile = data; 237 ASSERT(data && range); 238 239 range[0] = MMIN(profile->a[0], profile->a[1]); 240 range[0] = MMIN(MMIN(profile->b[0], profile->b[1]), range[0]); 241 range[0] = MMIN(MMIN(profile->c[0], profile->c[1]), range[0]); 242 243 range[1] = MMAX(profile->a[0], profile->a[1]); 244 range[1] = MMAX(MMAX(profile->b[0], profile->b[1]), range[1]); 245 range[1] = MMAX(MMAX(profile->c[0], profile->c[1]), range[1]); 246 247 return range; 248 }