|
k-dot-p 0.1
|
00001 /* 00002 *oneoff_1d_argprocess: process args for oneoff_1d 00003 00004 Copyright (C) 2010 Joseph Pingenot 00005 00006 This program is free software: you can redistribute it and/or modify 00007 it under the terms of the GNU Affero General Public License as published by 00008 the Free Software Foundation, either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU Affero General Public License for more details. 00015 00016 You should have received a copy of the GNU Affero General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 00019 */ 00020 00021 /*The following will be stripped out in the MPI-enabled file*/ 00022 #undef HAVE_MPI 00023 00024 #include "oneoff_optimize_1d_argprocess.h++" 00025 #include <math.h> 00026 #include <stdio.h> 00027 #include <glib.h> 00028 #include <gio/gio.h> 00029 #include <gio/gunixinputstream.h> 00030 #include <stdlib.h> 00031 #include "kdotp/makestruct_argprocess.h++" 00032 #include <libmodelxx/function_specification.h++> 00033 #include "config.h" 00034 00035 using namespace kdotp::libmodelxx::postprocessing; 00036 00037 extern "C" { 00038 void program_print_version(FILE* f); 00039 void libkdotp_print_version(FILE* f); 00040 void libmodelxx_print_version(FILE* f); 00041 void liblapackwrap_print_version(FILE* f); 00042 void libpostproc_print_version(FILE* f); 00043 void libpostproccalx_print_version(FILE* f); 00044 } 00045 00046 void print_version_info(void) { 00047 program_print_version(stdout); 00048 libmodelxx_print_version(stdout); 00049 libkdotp_print_version(stdout); 00050 liblapackwrap_print_version(stdout); 00051 libpostproc_print_version(stdout); 00052 libpostproc_print_version(stdout); 00053 libpostproccalx_print_version(stdout); 00054 printf("autotools info:\n\tProject: %s\n\tVersion: %s\n", PACKAGE_NAME, VERSION); 00055 } 00056 00057 struct template_parameter_range* new_template_parameter_range(char* name, double from, double to, double step) { 00058 struct template_parameter_range *tpr = (struct template_parameter_range*)malloc(sizeof(template_parameter_range)); 00059 if(tpr == NULL) return NULL; 00060 tpr->symbol = name; 00061 tpr->from = from; 00062 tpr->to = to; 00063 tpr->stepsize = step; 00064 return tpr; 00065 } 00066 00067 /**Returns a pointer to a malloc'ed double if successful, 00068 * else returns NULL 00069 */ 00070 double* get_double_for_string(const char* s) { 00071 double v; 00072 int n = sscanf(s, "%lg", &v); 00073 if(n != 1) return NULL; 00074 double* pv = (double*)malloc(sizeof(double)); 00075 if(pv == NULL) return NULL; 00076 *pv = v; 00077 return pv; 00078 } 00079 unsigned* get_unsigned_for_string(const char* s) { 00080 unsigned v; 00081 int n = sscanf(s, "%u", &v); 00082 if(n != 1) return NULL; 00083 unsigned* pv = (unsigned*)malloc(sizeof(unsigned)); 00084 if(pv == NULL) return NULL; 00085 *pv = v; 00086 return pv; 00087 } 00088 00089 00090 /**Sets a quikmat from a string. 00091 *\param m ptr to a quikmat struct 00092 *\param matstring string to convert from 00093 *\return non-zero if there was an error; zero if success 00094 */ 00095 int set_quikmat(struct quikmat* m, char* matstring) { 00096 char** matpieces; 00097 matpieces = g_strsplit(matstring, "/", 4); 00098 if(matpieces[0] == NULL) { 00099 /*This is a single material.*/ 00100 GString* s = g_string_new(matstring); 00101 m->mat1 = s->str; 00102 g_string_free(s, FALSE); 00103 m->mat2 = NULL; 00104 m->x = 1.0; 00105 return 0; 00106 } 00107 GString* s = g_string_new(matpieces[0]); 00108 m->mat1 = s->str; 00109 g_string_free(s, FALSE); 00110 if(matpieces[1] == NULL) { 00111 /*Again a single material. Ship it.*/ 00112 m->mat2 = NULL; 00113 m->x = 1.0; 00114 return 0; 00115 } 00116 int val = sscanf(matpieces[1], "%lg", &(m->x)); 00117 if((val != 1) || isnan(m->x) || isinf(m->x) || (m->x <=0) || (m->x >= 1)) { 00118 fprintf(stderr, "Got invalid number %g (%s) as material percentage in material string (%s)\n", m->x, matpieces[1], matstring); 00119 m->mat2 = NULL; 00120 return 1; 00121 } 00122 if(matpieces[2] == NULL) { 00123 fprintf(stderr, "Got no second alloy material in material string (%s)\n", matstring); 00124 m->mat2 = NULL; 00125 return 2; 00126 } 00127 m->mat2 = matpieces[2]; 00128 return 0; 00129 } 00130 00131 int process_args(int argc, char** argv, struct args* args) { 00132 int errored = 0; 00133 gchar **file_names = NULL; 00134 gboolean print_version = FALSE; 00135 gchar** parameters=NULL; 00136 GString *s = g_string_new("/home/solarion/dist/share/materials-databases/matdb.txt"); 00137 args->matdb = s->str; 00138 args->N_starting_points=10; 00139 /*Set the random seed value to a random value (done internally when seed is 0) by default*/ 00140 args->seed_value=0; 00141 args->blocksize=4; 00142 g_string_free(s, FALSE); 00143 s = g_string_new("OptimizerMaterial"); 00144 args->optimizer_material = s->str; 00145 args->continuous = FALSE; 00146 #ifdef HAVE_MPI 00147 args->mpi = FALSE; 00148 args->temperature = 0; 00149 args->anneal_start = 0; 00150 args->anneal_end = 0; 00151 args->num_anneal_steps = 0; 00152 args->anneal_cycles = 0; 00153 args->calculation_steps_per_annealing_step = 0; 00154 #endif 00155 g_string_free(s, FALSE); 00156 char* mdb = NULL; 00157 char* optmat = NULL; 00158 int raw_startingpoints = 10; 00159 char* mat1=NULL; 00160 char* mat0=NULL; 00161 char* assignments = NULL; 00162 args->assignments = NULL; 00163 args->assignment_expr = NULL; 00164 int raw_blocksize; 00165 args->minx=0.0; 00166 args->maxx=1.0; 00167 args->stepsize=0.1; 00168 args->min_stepsize=0.001; 00169 args->multiplier=0.33; 00170 args->N_blocks = 0; 00171 args->do_nofield_comparison = FALSE; 00172 char* annealing_program=NULL; 00173 GOptionEntry options[] = { 00174 { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &file_names,}, 00175 { "version", 'v', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_NONE, &print_version, "Print version information about this program", NULL }, 00176 { "matdb", 'm', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING, &(mdb), "Use an alternate materials database file.", NULL }, 00177 {"parameter", 'p', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING_ARRAY, ¶meters, "Provide a template parameter argument, in the form param,value (single value) or param,start,stop,step (sequence)\n", NULL}, 00178 { "optmat", 'o', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING, &(optmat), "Material name specifying the region to be optimized", NULL }, 00179 { "mat1", '1', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING, &(mat1), "Material name specifying one material to use in the optimizer. Must be of the form mata/x/matb for alloys of MatA_x MatB_{1-x}.", NULL }, 00180 { "mat0", '0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING, &(mat0), "Material name specifying the other material to be used in the optimizer. Must be of the form mata/x/matb for alloys of MatA_x MatB_{1-x}.", NULL }, 00181 { "startingpoints", 's', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &(raw_startingpoints), "Number of random starting structures", NULL }, 00182 { "blocksize", 'b', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &(raw_blocksize), "Size of a block of material in gridsites (optimization is done in blocks for accuracy; ignored if num_blocks is set to a nonzero value)", NULL }, 00183 { "num_blocks", 'B', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &(args->N_blocks), "Number of blocks to use (leave unspecified to use blocksize instead)", NULL }, 00184 /*The seed can be signed here; this will allow full access to the bits*/ 00185 { "seed", 'S', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT64, (long unsigned*)&(args->seed_value), "Seed to use for the random number generator (to reproduce a run; default is random)", NULL }, 00186 { "minx", 'x', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_DOUBLE, &(args->minx), "Minimum allowable alloying for continuous alloying. (default is 0; ignored for digital alloys)", NULL}, 00187 { "maxx", 'X', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_DOUBLE, &(args->maxx), "Maximum allowable alloying for continuous alloying (default is 1; ignored for digital alloys)", NULL}, 00188 { "multiplier", 'u', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_DOUBLE, &(args->multiplier), "Alloying step multiplier (sets the next alloying stepsize after a successful optimization at one alloying stepsize) for continuous alloying (ignored for digital alloys)", NULL}, 00189 { "stepsize", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_DOUBLE, &(args->stepsize), "Initial alloying step size (how much to change x for the first optimization step; subsequent steps are set by stepsize=multiplier*stepsize) for continuous alloying (ignored for digital alloys)", NULL}, 00190 { "converged_stepsize", 'T', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_DOUBLE, &(args->min_stepsize), "Consider alloying converged when stepsize reaches this value or smaller for continuous alloying (ignored for digital alloys)", NULL}, 00191 {"assignments", 'a', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING, &assignments, "Provide initial material assignments. Can be a single float, a comma-separated list of floats, or a function. If digital alloying, 0 <= v < 0.5 is assigned 0; 0.5 <= v <= 1.0 is assigned 1.\n", NULL}, 00192 { "continuous", 'c', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_NONE, &(args->continuous), "Do a continuous optimization, not a digital alloying. NOTE that mat1 and mat2 must be a single material, not an alloy", NULL }, 00193 #ifdef HAVE_MPI 00194 { "mpi", 'M', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_NONE, &(args->mpi), "Use the MPI variant of the digital alloying algorithm. Currently ignored for continuous optimization. If an annealing option is not given, it uses a steepest-descent-related Monte Carlo method.", NULL }, 00195 { "anneal-temperature", 'A', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_DOUBLE, &(args->temperature), "If specified, simulated annealing will be used at the specified temperature instead of the steepest-descent mode. Requires the MPI option. Temperature is in units of 1e-13 eV m.", NULL }, 00196 { "annealing-program", 'P', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING, &(annealing_program), "If specified, simulated annealing will be used with the specified program instead of the steepest-descent mode. Requires the MPI option. The program is specified in the form of num_cycles,start_temperature,stop_temperature,num_temperature_steps. Temperature is in units of 1e-13 eV m.", NULL }, 00197 #endif 00198 { "compare_noefield", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_NONE, &(args->do_nofield_comparison), "Instead of simply optimizing alpha, optimize the *change* in alpha between the structure as specified and the structure with no applied electric field.", NULL }, 00199 /*At some point, we should allow for a starting point*/ 00200 {NULL} 00201 }; 00202 GOptionContext *ctx; 00203 ctx = g_option_context_new("- sets up a structure for k-dot-p calculations"); 00204 g_option_context_add_main_entries(ctx, options, "Options"); 00205 00206 g_option_context_parse(ctx, &argc, &argv, NULL); 00207 00208 gchar* htext = g_option_context_get_help(ctx, FALSE, NULL); 00209 g_option_context_free(ctx); 00210 00211 if(mdb != NULL) { 00212 free(args->matdb); 00213 args->matdb = mdb; 00214 } 00215 if(optmat != NULL) { 00216 free(args->optimizer_material); 00217 args->optimizer_material = optmat; 00218 } 00219 00220 #ifdef HAVE_MPI 00221 if(args->temperature != 0) args->temperature *= 1e-13; 00222 if((args->temperature != 0) && (annealing_program != NULL)) { 00223 fprintf(stderr, "ERROR: both a fixed annealing temperature as well as an annealing program were specified! Only one may be given at a time.\n"); 00224 errored=1; 00225 } 00226 if(annealing_program != NULL) { 00227 char** segments; 00228 int N_temp_steps; 00229 segments = g_strsplit(annealing_program, ",", 5); 00230 if(segments == NULL) { 00231 fprintf(stderr, "ERROR: unable to break the specified annealing program (%s) into comma-delimited parts.\n", annealing_program); 00232 errored=1; 00233 }else if(segments[0] == NULL) { 00234 fprintf(stderr, "ERROR: unable to find the number of annealing cycles in the annealing program (%s).\n", annealing_program); 00235 errored=1; 00236 }else if(segments[1] == NULL) { 00237 fprintf(stderr, "ERROR: unable to find the starting temperature in the annealing program (%s).\n", annealing_program); 00238 errored=1; 00239 }else if(segments[2] == NULL) { 00240 fprintf(stderr, "ERROR: unable to find the stopping temperature in the annealing program (%s).\n", annealing_program); 00241 errored=1; 00242 }else if(segments[3] == NULL) { 00243 fprintf(stderr, "ERROR: unable to find the number of temperature steps per cycle in the annealing program (%s).\n", annealing_program); 00244 errored=1; 00245 }else if(segments[4] == NULL) { 00246 fprintf(stderr, "ERROR: unable to find the number of calculations per annealing step in the annealing program (%s).\n", annealing_program); 00247 errored=1; 00248 }else{ 00249 /*All the values are there; calculate them*/ 00250 double* dv; 00251 unsigned* iv; 00252 iv = get_unsigned_for_string(segments[0]); 00253 if(iv == NULL) { 00254 fprintf(stderr, "ERROR: unable to find an unsigned integer for the number of annealing cycles (%s).\n", segments[0]); 00255 errored=1; 00256 }else{ 00257 args->anneal_cycles = *iv; 00258 if(*iv == 0) { 00259 fprintf(stderr, "ERROR: specifying 0 annealing cycles is useless; I'm assuming this was in error.\n"); 00260 errored=1; 00261 } 00262 free(iv); 00263 } 00264 dv = get_double_for_string(segments[1]); 00265 if(dv == NULL) { 00266 fprintf(stderr, "ERROR: unable to find an double-precision number for the annealing cycle start (%s).\n", segments[1]); 00267 errored=1; 00268 }else{ 00269 args->anneal_start = *dv*1e-13; 00270 if(args->anneal_start <= 0) { 00271 fprintf(stderr, "ERROR: annealing cycle starting temperature must be > 0 (got %g).\n", *dv); 00272 errored=1; 00273 } 00274 free(dv); 00275 } 00276 dv = get_double_for_string(segments[2]); 00277 if(dv == NULL) { 00278 fprintf(stderr, "ERROR: unable to find an double-precision number for the annealing cycle end (%s).\n", segments[2]); 00279 errored=1; 00280 }else{ 00281 args->anneal_end = *dv*1e-13; 00282 if(args->anneal_start <= 0) { 00283 fprintf(stderr, "ERROR: annealing cycle ending temperature must be > 0 (got %g).\n", *dv); 00284 errored=1; 00285 } 00286 if(args->anneal_start >= args->anneal_end) { 00287 fprintf(stderr, "ERROR: annealing starting temperature (%g) is greater than or equal to the ending temperature (%g)!\n", args->anneal_start, args->anneal_end); 00288 errored=1; 00289 } 00290 free(dv); 00291 } 00292 iv = get_unsigned_for_string(segments[3]); 00293 if(iv == NULL) { 00294 fprintf(stderr, "ERROR: unable to find an unsigned integer for the number of annealing steps per cycle (%s).\n", segments[3]); 00295 errored=1; 00296 }else{ 00297 args->num_anneal_steps = *iv; 00298 if(*iv == 0) { 00299 fprintf(stderr, "ERROR: specifying 0 annealing steps is useless; I'm assuming this was in error.\n"); 00300 errored=1; 00301 } 00302 free(iv); 00303 } 00304 iv = get_unsigned_for_string(segments[4]); 00305 if(iv == NULL) { 00306 fprintf(stderr, "ERROR: unable to find an unsigned integer for the number of calculation steps per annealing step (%s).\n", segments[4]); 00307 errored=1; 00308 }else{ 00309 args->calculation_steps_per_annealing_step = *iv; 00310 if(*iv == 0) { 00311 fprintf(stderr, "ERROR: specifying 0 calculations per annealing step is useless; I'm assuming this was in error.\n"); 00312 errored=1; 00313 } 00314 free(iv); 00315 } 00316 } 00317 } 00318 #endif 00319 00320 if(raw_startingpoints <= 0) { 00321 fprintf(stderr, "ERROR: starting points given (%d) was less than or equal to zero! This is nonsensical.\n", raw_startingpoints); 00322 errored=1; 00323 }else{ 00324 args->N_starting_points=raw_startingpoints; 00325 } 00326 if(raw_blocksize <= 0) { 00327 fprintf(stderr, "ERROR: block size (%d) given was less than or equal to zero! This is nonsensical.\n", raw_blocksize); 00328 errored=1; 00329 }else{ 00330 args->blocksize=raw_blocksize; 00331 } 00332 00333 if((mat1 == NULL) || (mat0 == NULL)) { 00334 fprintf(stderr, "ERROR: you MUST supply the two material types for the digital alloy optimizer.\n"); 00335 errored=1; 00336 }else{ 00337 fprintf(stderr, "mat1=(%s) mat0=(%s)\n", mat1, mat0); 00338 errored=set_quikmat(&(args->mat1), mat1); 00339 errored=set_quikmat(&(args->mat0), mat0); 00340 } 00341 00342 args->filestreams = NULL; 00343 GFileInputStream *instream; 00344 GError *gerr = NULL; 00345 if(file_names != NULL) { 00346 for(int i = 0; file_names[i] != NULL; i++) { 00347 struct file_info *fi = (struct file_info*)malloc(sizeof(struct file_info)); 00348 if(fi == NULL) { 00349 fprintf(stderr, "ERROR: unable to allocate input file info struct!\n"); 00350 return 500; 00351 } 00352 if((file_names[i][0] == '-') && (file_names[i][1] == '\0')) { 00353 fi->instream = (GInputStream*)g_unix_input_stream_new(0, FALSE); 00354 fi->filename = g_string_new("-"); 00355 }else{ 00356 GFile *f = g_file_new_for_commandline_arg(file_names[i]); 00357 gerr = NULL; 00358 instream = g_file_read(f, NULL, &gerr); 00359 if(gerr != NULL) { 00360 fprintf(stderr, "makestruct: ERROR reading in structure file (%s): %s", g_file_get_uri(f), gerr->message); 00361 return 100; 00362 } 00363 g_object_unref(f); 00364 fi->instream = (GInputStream*)instream; 00365 fi->filename = g_string_new(file_names[i]); 00366 } 00367 args->filestreams = g_list_append(args->filestreams, fi); 00368 } 00369 } 00370 if(args->filestreams == NULL) { 00371 fprintf(stderr, "ERROR: you MUST give at least one file to process!\n"); 00372 errored=1; 00373 } 00374 00375 if(args->continuous) { 00376 if(args->mat1.x != 1) { 00377 fprintf(stderr, "ERROR: you MUST not give an alloy for continuous alloying (material 1 was an alloy.)\n"); 00378 errored=1; 00379 } 00380 if(args->mat0.x != 1) { 00381 fprintf(stderr, "ERROR: you MUST not give an alloy for continuous alloying (material 0 was an alloy.)\n"); 00382 errored=1; 00383 } 00384 } 00385 00386 if(assignments != NULL) { 00387 char** strs = g_strsplit(assignments, ",", -1); 00388 if(strs[0] == NULL) { 00389 fprintf(stderr, "ERROR: initial material assignment argument was given, but no data was!\n"); 00390 errored == 1; 00391 }else{ 00392 /*Try to convert the first argument into a double. If we can't, it's an equation.*/ 00393 double* pv = get_double_for_string(strs[0]); 00394 if(pv == NULL) { 00395 if(strs[1] != NULL) { 00396 /*Need to set up the equation parser*/ 00397 fprintf(stderr, "ERROR: First number given was not a float (%s), but you provided multiple arguments! You may only specify one equation to use for initial material assignments.\n", strs[0]); 00398 errored == 1; 00399 }else{ 00400 /*Need to set up the equation parser*/ 00401 fprintf(stderr, "ERROR: Equations are not yet supported. Sorry. One thing at a time.\n"); 00402 errored == 1; 00403 } 00404 } 00405 /*If the first arg wasn't an equation, we're good.*/ 00406 if(pv != NULL) { 00407 free(pv); 00408 for(unsigned i=0; strs[i] != NULL; i++) { 00409 double* pv = get_double_for_string(strs[i]); 00410 if(pv == NULL) { 00411 fprintf(stderr, "ERROR: Unable to convert %udth number (%s) to a float!\n", i, strs[i]); 00412 errored == 1; 00413 break; 00414 } 00415 /*OK. I'm a softie. <0.5 => 0; >=0.5 => 1*/ 00416 if(args->continuous) { 00417 if(*pv < 0.5) { 00418 *pv = 0.0; 00419 }else{ 00420 *pv = 1.0; 00421 } 00422 } 00423 args->assignments = g_list_append(args->assignments, pv); 00424 } 00425 } 00426 } 00427 g_strfreev(strs); 00428 } 00429 00430 char** tparam_entry; 00431 args->template_parameters = NULL; 00432 if(parameters != NULL) { 00433 for(unsigned i=0; parameters[i] != NULL; i++) { 00434 tparam_entry = g_strsplit(parameters[i], ",", -1); 00435 int len=g_strv_length(tparam_entry); 00436 struct template_parameter_range* tpr; 00437 if(len == 2) { 00438 /*parameter,value form*/ 00439 tpr = new_template_parameter_range(tparam_entry[0], strtod(tparam_entry[1], NULL), strtod(tparam_entry[1], NULL), strtod(tparam_entry[1], NULL)); 00440 }else if(len == 4) { 00441 tpr = new_template_parameter_range(tparam_entry[0], strtod(tparam_entry[1], NULL), strtod(tparam_entry[2], NULL), strtod(tparam_entry[3], NULL)); 00442 }else{ 00443 fprintf(stderr, "ERROR: invalid parameteter entry: incorrect number of parameter range arguments (got %d; expected 2 or 4; should be either parameter,value or parameter,start,stop,step)", len); 00444 return 15; 00445 } 00446 if(tpr == NULL) { 00447 fprintf(stderr, "ERROR: unable to allocate space for new template parameter range (parameter is %s)\n", tparam_entry[0]); 00448 return 16; 00449 } 00450 args->template_parameters = g_list_append(args->template_parameters, tpr); 00451 } 00452 } 00453 00454 if(print_version){ 00455 print_version_info(); 00456 return 1; 00457 } 00458 if(errored){ 00459 printf("%s", htext); 00460 printf("\n\n**For version and compilation information, run with --version***\n"); 00461 return 3; 00462 } 00463 return 0; 00464 }