k-dot-p 0.1

oneoff_optimize_1d_argprocess.c++

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