gimme-alpha 0.1

matdb.c

Go to the documentation of this file.
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 }
 All Classes Files Functions Variables Enumerations Enumerator Defines