|
gimme-alpha 0.1
|
00001 /* 00002 * matdb: generic materials database information. 00003 00004 00005 00006 Copyright (C) 2008 Joseph Pingenot 00007 00008 This program is free software: you can redistribute it and/or modify 00009 it under the terms of the GNU Affero General Public License as published by 00010 the Free Software Foundation, either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU Affero General Public License for more details. 00017 00018 You should have received a copy of the GNU Affero General Public License 00019 along with this program. If not, see <http://www.gnu.org/licenses/>. 00020 00021 */ 00022 00023 #include <stdio.h> 00024 #include <stdlib.h> 00025 #include <string.h> 00026 #include <libmodeling/matdb.h> 00027 00028 #define ALLOY_PERCENT_MAX_FIELD_LENGTH 9 00029 00030 static guint g_string_hash2(gconstpointer p) { 00031 return g_str_hash(((GString*)p)->str); 00032 } 00033 00034 static gboolean g_string_equal2(gconstpointer a, gconstpointer b) { 00035 return g_str_equal(((GString*)a)->str, ((GString*)b)->str); 00036 } 00037 00038 static void destroy_double(gpointer data){ 00039 free((double*)data); 00040 } 00041 static void destroy_gstring(gpointer data){ 00042 g_string_free((GString*)data, TRUE); 00043 } 00044 static void destroy_hashtable(gpointer data){ 00045 g_hash_table_destroy((GHashTable*)data); 00046 } 00047 00048 static void print_property(gpointer key, gpointer value, gpointer user_data) { 00049 fprintf(stderr, "\t\t%s=%g:\n", (char*)key, *(double*)value); 00050 } 00051 00052 static void print_inner_bowing(gpointer key, gpointer value, gpointer user_data) { 00053 fprintf(stderr, "\t%s/%s:\n", ((GString*) key)->str, ((GString*)user_data)->str); 00054 g_hash_table_foreach((GHashTable*)value, &print_property, NULL); 00055 } 00056 00057 static void print_material(gpointer key, gpointer value, gpointer user_data) { 00058 fprintf(stderr, "\tmaterial %s:\n", ((GString*)key)->str); 00059 g_hash_table_foreach((GHashTable*)value, &print_property, NULL); 00060 } 00061 00062 static void print_bowing(gpointer key, gpointer value, gpointer user_data) { 00063 g_hash_table_foreach((GHashTable*)value, &print_inner_bowing, key); 00064 } 00065 00066 void print_matdb(const struct matdb *mdb) { 00067 fprintf(stderr, "matdb/MATERIALS:\n"); 00068 g_hash_table_foreach(mdb->materials, &print_material, NULL); 00069 fprintf(stderr, "matdb/BOWINGS:\n"); 00070 g_hash_table_foreach(mdb->bowings, &print_bowing, NULL); 00071 } 00072 00073 /*ERROR CODES: 00074 0: success 00075 1: (not defined) 00076 2: mat1 doesn't exist. 00077 3: mat1 param doesn't exist. 00078 4: mat2 doesn't exist. 00079 5: mat2 param doesn't exist. 00080 */ 00081 double get_alloy_param(const struct matdb *mdb, const char* mat1, const char* mat2, double x, const char* param, int *err) { 00082 //fprintf(stderr, "get_alloy_param(%s, %s, %g, %s):", mat1, mat2, x, param); 00083 GString* m1 = g_string_new(mat1); 00084 GString* m2 = g_string_new(mat2); 00085 GString* p = g_string_new(param); 00086 GHashTable *ppts; 00087 GHashTable *ppts1; 00088 GHashTable *ppts2; 00089 double *v1; 00090 double *v2; 00091 double *bow = NULL; 00092 /*is a hash indexed by the first material, containing a hash indexed 00093 * by the second material.*/ 00094 if((ppts = g_hash_table_lookup(mdb->bowings, m1)) == NULL) { 00095 /*If there's no bowing param, we just use a linear interpolation.*/ 00096 if((ppts = g_hash_table_lookup(mdb->bowings, m2)) != NULL) { 00097 ppts = g_hash_table_lookup(ppts, m1); 00098 } 00099 }else{ 00100 ppts = g_hash_table_lookup(ppts, m2); 00101 } 00102 if(ppts != NULL) { 00103 bow = g_hash_table_lookup(ppts, p); 00104 } 00105 if(unlikely((ppts1 = g_hash_table_lookup(mdb->materials, m1)) == NULL)) { 00106 *err = 2; 00107 g_string_free(m1, TRUE); 00108 g_string_free(m2, TRUE); 00109 g_string_free(p, TRUE); 00110 return 0; 00111 }else{ 00112 if(unlikely((v1 = g_hash_table_lookup(ppts1, p)) == NULL)) { 00113 *err = 3; 00114 g_string_free(m1, TRUE); 00115 g_string_free(m2, TRUE); 00116 g_string_free(p, TRUE); 00117 return 0; 00118 } 00119 } 00120 if(unlikely((ppts2 = g_hash_table_lookup(mdb->materials, m2)) == NULL)) { 00121 *err = 4; 00122 g_string_free(m1, TRUE); 00123 g_string_free(m2, TRUE); 00124 g_string_free(p, TRUE); 00125 return 0; 00126 }else{ 00127 if(unlikely((v2 = g_hash_table_lookup(ppts2, p)) == NULL)) { 00128 *err = 5; 00129 g_string_free(m1, TRUE); 00130 g_string_free(m2, TRUE); 00131 g_string_free(p, TRUE); 00132 return 0; 00133 } 00134 } 00135 *err = 0; 00136 if(bow != NULL) { 00137 //fprintf(stderr, "bow=%g alloy=%g\n", *bow, alloy_bowed(*v1, *v2, *bow, x)); 00138 g_string_free(m1, TRUE); 00139 g_string_free(m2, TRUE); 00140 g_string_free(p, TRUE); 00141 return alloy_bowed(*v1, *v2, *bow, x); 00142 }else{ 00143 //fprintf(stderr, "bow=[none] alloy=%g\n", alloy_linear(*v1, *v2, x)); 00144 g_string_free(m1, TRUE); 00145 g_string_free(m2, TRUE); 00146 g_string_free(p, TRUE); 00147 return alloy_linear(*v1, *v2, x); 00148 } 00149 } 00150 00151 /*ERROR CODES: 00152 * 0: success 00153 * 1: no such material 00154 * 2: material doesn't have param. 00155 */ 00156 double get_material_param(const struct matdb *mdb, const char* mat, const char* param, int *err) { 00157 GString* m = g_string_new(mat); 00158 GString* p = g_string_new(param); 00159 GHashTable *ppts; 00160 double* v; 00161 //fprintf(stderr, "get_material_param: m=%s p=%s\n", m->str, p->str); 00162 ppts = g_hash_table_lookup(mdb->materials, m); 00163 if(likely(ppts != NULL)) { 00164 if(unlikely((v = g_hash_table_lookup(ppts, p)) == NULL)) { 00165 *err = 2; 00166 g_string_free(m, TRUE); 00167 g_string_free(p, TRUE); 00168 return 0; 00169 } 00170 }else{ 00171 *err = 1; 00172 g_string_free(m, TRUE); 00173 g_string_free(p, TRUE); 00174 return 0; 00175 } 00176 *err = 0; 00177 g_string_free(m, TRUE); 00178 g_string_free(p, TRUE); 00179 return *v; 00180 } 00181 00182 /*ERROR CODES: 00183 * 0: success 00184 * 1: couldn't allocate space for storing the value 00185 * 3: (debug only) property already exists 00186 */ 00187 void set_material_param(struct matdb *mdb, const char* mat, const char* param, double value, int *err) { 00188 GString *p = g_string_new(param); 00189 GString *m = g_string_new(mat); 00190 GHashTable *ppts; 00191 //fprintf(stderr, "set_material_param: m=%s p=%s, value=%g\n", m->str, p->str, value); 00192 if((ppts = g_hash_table_lookup(mdb->materials, m)) == NULL) { 00193 /*Make a new structure.*/ 00194 ppts = g_hash_table_new_full(g_string_hash2, g_string_equal2, destroy_gstring, destroy_double); 00195 g_hash_table_insert(mdb->materials, m, ppts); 00196 }else{ 00197 g_string_free(m, TRUE); 00198 } 00199 double *v = (double*)malloc(sizeof(double)); 00200 if(v == NULL) { 00201 *err = 1; 00202 g_string_free(m, TRUE); 00203 g_string_free(p, TRUE); 00204 return; 00205 } 00206 #ifdef DEBUG 00207 if(unlikely(g_hash_table_lookup(ppts, p) != NULL)) { 00208 *err = 3; 00209 }else{ 00210 #endif 00211 *err = 0; 00212 #ifdef DEBUG 00213 } 00214 #endif 00215 *v = value; 00216 g_hash_table_insert(ppts, p, v); 00217 } 00218 00219 /*ERROR CODES: 00220 * 0: success 00221 * 1: mat1 doesn't (yet?) exist 00222 * 2: mat1 param doesn't (yet?) exist 00223 * 3: mat2 doesn't (yet?) exist 00224 * 4: mat2 param doesn't (yet?) exist 00225 */ 00226 void set_bowing_param(struct matdb *mdb, const char* mat1, const char* mat2, const char* param, double value, int *err) { 00227 //fprintf(stderr, "set_bowing_param(%s, %s, %s, %g) ", mat1, mat2, param, value); 00228 GString *p = g_string_new(param); 00229 GString *p2 = g_string_new(param); 00230 GString *m1 = g_string_new(mat1); 00231 GString *m2 = g_string_new(mat2); 00232 /*for the 2nd-level table*/ 00233 GString *m1_2 = g_string_new(mat1); 00234 GString *m2_2 = g_string_new(mat2); 00235 GHashTable *ppts; 00236 GHashTable *ppts2; 00237 double *v; 00238 /*First, ensure that the property has been set for both m1 and mat2.*/ 00239 if(unlikely((ppts = g_hash_table_lookup(mdb->materials, m1)) == NULL)){ 00240 //fprintf(stderr, "!mat1 (err1)\n"); 00241 *err = 1; 00242 return; 00243 } 00244 if(unlikely((v = g_hash_table_lookup(ppts, p)) == NULL)){ 00245 //fprintf(stderr, "!mat1/param (err2)\n"); 00246 *err = 2; 00247 return; 00248 } 00249 if(unlikely((ppts2 = g_hash_table_lookup(mdb->materials, m2)) == NULL)){ 00250 //fprintf(stderr, "!mat2 (err3)\n"); 00251 *err = 3; 00252 return; 00253 } 00254 if(unlikely((v = g_hash_table_lookup(ppts2, p)) == NULL)){ 00255 //fprintf(stderr, "!mat2/param (err4)\n"); 00256 *err = 4; 00257 return; 00258 } 00259 GHashTable *l2_table; 00260 GHashTable *l2_table2; 00261 /*We ensure that the bowings are set for both m1->m2 and m2->m1*/ 00262 if((l2_table = g_hash_table_lookup(mdb->bowings, m1)) == NULL) { 00263 /*Make a new structure.*/ 00264 l2_table = g_hash_table_new_full(g_string_hash2, g_string_equal2, destroy_gstring, destroy_hashtable); 00265 g_hash_table_insert(mdb->bowings, m1, l2_table); 00266 }else{ 00267 g_string_free(m1, TRUE); 00268 } 00269 /*Make sure that, if need be, there's a struct for the other way.*/ 00270 if((l2_table2 = g_hash_table_lookup(mdb->bowings, m2)) == NULL) { 00271 /*Make a new structure.*/ 00272 l2_table2 = g_hash_table_new_full(g_string_hash2, g_string_equal2, destroy_gstring, destroy_hashtable); 00273 g_hash_table_insert(mdb->bowings, m2, l2_table2); 00274 }else{ 00275 g_string_free(m2, TRUE); 00276 } 00277 /*We can't just have m1,m2 and m2,m1 point to the same hash 00278 * table; Otherwise, on deletion (and therefore on inserting 00279 * duplicate data), the structure will be freed/destroyed twice! 00280 */ 00281 if((ppts = g_hash_table_lookup(l2_table, m2_2)) == NULL) { 00282 /*Need to make a hash for the properties.*/ 00283 ppts = g_hash_table_new_full(g_string_hash2, g_string_equal2, destroy_gstring, destroy_double); 00284 g_hash_table_insert(l2_table, m2_2, ppts); 00285 }else{ 00286 g_string_free(m2_2, TRUE); 00287 } 00288 if((ppts2 = g_hash_table_lookup(l2_table2, m1_2)) == NULL) { 00289 /*Need to make a hash for the properties.*/ 00290 ppts2 = g_hash_table_new_full(g_string_hash2, g_string_equal2, destroy_gstring, destroy_double); 00291 g_hash_table_insert(l2_table2, m1_2, ppts2); 00292 }else{ 00293 g_string_free(m1_2, TRUE); 00294 } 00295 /*Now we can insert the value into the ppts.*/ 00296 double *v1 = (double*)malloc(sizeof(double)); 00297 double *v2 = (double*)malloc(sizeof(double)); 00298 *v1 = *v2 = value; 00299 g_hash_table_insert(ppts, p, v1); 00300 g_hash_table_insert(ppts2, p2, v2); 00301 *err = 0; 00302 //fprintf(stderr, "\n"); 00303 } 00304 00305 double get_param(const struct matdb *mdb, const char* mat1, const char* mat2, double x, const char* param, int *err) { 00306 if(mat2 == NULL) return get_material_param(mdb, mat1, param, err); 00307 else return get_alloy_param(mdb, mat1, mat2, x, param, err); 00308 } 00309 00310 struct matdb* matdb_new() { 00311 struct matdb* mdb = (struct matdb*)malloc(sizeof(struct matdb)); 00312 if(mdb == NULL) return NULL; 00313 mdb->materials = g_hash_table_new_full(g_string_hash2, g_string_equal2, destroy_gstring, destroy_hashtable); 00314 if(mdb->materials == NULL) { 00315 free(mdb); 00316 return NULL; 00317 } 00318 mdb->bowings = g_hash_table_new_full(g_string_hash2, g_string_equal2, destroy_gstring, destroy_hashtable); 00319 if(mdb->bowings == NULL) { 00320 g_hash_table_destroy(mdb->materials); 00321 free(mdb); 00322 return NULL; 00323 } 00324 return mdb; 00325 } 00326 00327 void canonicalize_alloy_args(char **mat1, char **mat2, double *x) { 00328 if(((*x) < 0) || ((*x) > 1)) return; 00329 char* t; 00330 if(strcmp(*mat1, *mat2) >= 0) { 00331 t = *mat1; 00332 *mat1 = *mat2; 00333 *mat2 = t; 00334 *x = 1.0-(*x); 00335 } 00336 } 00337 GString* canonicalize_alloy(char **mat1, char **mat2, double *x) { 00338 if(((*x) < 0) || ((*x) > 1)) return NULL; 00339 GString *name; 00340 char x1[ALLOY_PERCENT_MAX_FIELD_LENGTH]; 00341 char x2[ALLOY_PERCENT_MAX_FIELD_LENGTH]; 00342 canonicalize_alloy_args(mat1, mat2, x); 00343 snprintf(x1, ALLOY_PERCENT_MAX_FIELD_LENGTH, "%.5f", *x); 00344 snprintf(x2, ALLOY_PERCENT_MAX_FIELD_LENGTH, "%.5f", (1.0-(*x))); 00345 x1[ALLOY_PERCENT_MAX_FIELD_LENGTH-1]='\0'; 00346 x2[ALLOY_PERCENT_MAX_FIELD_LENGTH-1]='\0'; 00347 name = g_string_new(*mat1); 00348 name = g_string_append(name, "_"); 00349 name = g_string_append(name, x1); 00350 name = g_string_append(name, "/"); 00351 name = g_string_append(name, *mat2); 00352 name = g_string_append(name, "_"); 00353 name = g_string_append(name, x2); 00354 return name; 00355 } 00356 00357 struct property_passthru { 00358 GHashTable *ppts2; 00359 GHashTable *bowings; 00360 GHashTable *final_ppts; 00361 double x; 00362 }; 00363 00364 static void assemble_properties_foreach(gpointer key, gpointer data, gpointer private) { 00365 struct property_passthru *pt = (struct property_passthru*)private; 00366 double *v; 00367 double *v2; 00368 double *bow = NULL; 00369 /*Make sure the property is set for material 2.*/ 00370 if((v2 = g_hash_table_lookup(pt->ppts2, (GString*)key)) == NULL) return; 00371 if(pt->bowings != NULL) bow = g_hash_table_lookup(pt->bowings, (GString*)key); 00372 v = (double*)malloc(sizeof(double)); 00373 if(bow != NULL) { 00374 *v = alloy_bowed(*(double*)key, *v2, *bow, pt->x); 00375 }else{ 00376 *v = alloy_linear(*(double*)key, *v2, pt->x); 00377 } 00378 } 00379 00380 struct material* get_alloy(const struct matdb *mdb, const char* mat1, const char* mat2, double x) { 00381 struct material* m; 00382 if((m= (struct material*)malloc(sizeof(struct material))) == NULL) return NULL; 00383 if((m->storage = (struct alloy_storage*)malloc(sizeof(struct alloy_storage))) == NULL) { 00384 free(m); 00385 return NULL; 00386 } 00387 char *mt1 = (char*)mat1; 00388 char *mt2 = (char*)mat2; 00389 double ex = x; 00390 m->name = canonicalize_alloy(&mt1, &mt2, &ex); 00391 00392 if(m->name == NULL) { 00393 free((struct material*)(m->storage)); 00394 free(m); 00395 return NULL; 00396 } 00397 GString *m1 = g_string_new(mat1); 00398 GString *m2 = g_string_new(mat2); 00399 GHashTable *ppts1 = g_hash_table_lookup(mdb->materials, m1); 00400 GHashTable *ppts2 = g_hash_table_lookup(mdb->materials, m2); 00401 GHashTable *bowings = g_hash_table_lookup(mdb->bowings, m1); 00402 if(bowings != NULL) bowings = g_hash_table_lookup(bowings, m2); 00403 GHashTable *final_ppts = g_hash_table_new_full(g_string_hash2, g_string_equal2, destroy_gstring, destroy_double); 00404 if((m->name == NULL) || (final_ppts == NULL) || (ppts1 == NULL) || (ppts2 == NULL)) { 00405 g_string_free(m1, TRUE); 00406 g_string_free(m2, TRUE); 00407 if(final_ppts != NULL) g_hash_table_destroy(final_ppts); 00408 free((struct material*)(m->storage)); 00409 free(m); 00410 return NULL; 00411 } 00412 struct property_passthru pt; 00413 pt.ppts2 = ppts2; 00414 pt.bowings = bowings; 00415 pt.final_ppts = final_ppts; 00416 pt.x = ex; 00417 g_hash_table_foreach(ppts1, assemble_properties_foreach, &pt); 00418 g_string_free(m1, TRUE); 00419 g_string_free(m2, TRUE); 00420 ((struct alloy_storage*)m->storage)->ppts = final_ppts; 00421 ((struct alloy_storage*)m->storage)->mat1 = m1; 00422 ((struct alloy_storage*)m->storage)->mat2 = m2; 00423 ((struct alloy_storage*)m->storage)->x = ex; 00424 return m; 00425 } 00426 00427 void matdb_destroy(struct matdb* mdb) { 00428 g_hash_table_destroy(mdb->materials); 00429 g_hash_table_destroy(mdb->materials); 00430 }