#include #include #include #include #include "mdutil.h" #include "simfront.h" #include "sfconfig.h" /* * expand macros into assignment functions for SimFront parameters * (macros defined in sfconfig.h) */ SET_STRLIST(paramfilelist, paramfilelistnum, paramfilelistmax) SET_STRING(topofile) SET_STRING(coorfile) SET_STRING(bincoorfile) SET_STRING(velfile) SET_STRING(binvelfile) SET_STRING(cwd) SET_STRING(outputfile) SET_BOOL(isoutputbin) SET_STRING(restartfile) SET_BOOL(isrestartbin) SET_INT(restartfreq) SET_INT(energyfreq) SET_INT(numsteps) SET_DOUBLE(temperature) /* * global constants */ const ConfigKeywd config_keywd_list[] = { { "parameters", set_paramfilelist }, { "structure", set_topofile }, { "coordinates", set_coorfile }, { "bincoordinates", set_bincoorfile }, { "velocities", set_velfile }, { "binvelocities", set_binvelfile }, { "cwd", set_cwd }, { "outputname", set_outputfile }, { "binaryoutput", set_isoutputbin }, { "restartname", set_restartfile }, { "binaryrestart", set_isrestartbin }, { "restartfreq", set_restartfreq }, { "outputenergies", set_energyfreq }, { "numsteps", set_numsteps }, { "temperature", set_temperature }, }; const int config_keywd_list_num = ARRLEN(config_keywd_list); /* * prototypes for internal functions */ static int set_default_cwd(SimFront *sf); static int read_config_file(SimFront *sf); static int parse_engine_param(SimFront*, const char*keywd, const char*value); static int postprocess_config(SimFront *sf); static int prepend_cwd(SimFront *sf, char **pfname); /* * called externally */ int setup_config(SimFront *sf) { /* set default current working directory as path of config file */ if (set_default_cwd(sf)) return -1; /* read in config file */ if (read_config_file(sf)) return -1; /* post process our configuration */ if (postprocess_config(sf)) return -1; return 0; } /* default current working directory is path of config file */ int set_default_cwd(SimFront *sf) { const char *fname = sf->configfile; char *cwd; int k; if (fname[0] != '/' && (fname[0] != '.' || fname[1] != '/')) { /* if path is relative, prepend "./" to be stored as path */ cwd = (char *) malloc(strlen(fname) + 3); if (cwd == NULL) { ERRMSG(sf, strerror(errno)); return -1; } strcpy(cwd, "./"); strcat(cwd, fname); } else { cwd = strdup(fname); if (cwd == NULL) { ERRMSG(sf, strerror(errno)); return -1; } } k = strlen(cwd) + 1; while (cwd[--k] != '/') ; cwd[k] = '\0'; sf->cwd = cwd; return 0; } /* * read in config file * each line contains: keyword value(s) * check keyword against SimFront first, then against engine names * call function to parse value from line */ int read_config_file(SimFront *sf) { char buf[256], save_keywd[256]; Config config; Config *pconfig = &config; Ihash *kwdtable = &(sf->kwdtable); const ConfigKeywd *cfkwd = sf->cfkwd; char *keywd, *value, *c; int k; if (config_init(pconfig)) { ERRMSG(sf, "call to config_init"); return -1; } else if (config_open(pconfig, sf->configfile)) { ERRMSG(sf, "call to config_open"); return -1; } while (config_read(pconfig, buf, sizeof(buf), &keywd, &value) > 0) { /* preserve original keyword */ strcpy(save_keywd, keywd); /* convert to lower case */ for (c = keywd; *c != '\0'; c++) *c = tolower(*c); /* first check our own hash table */ /* otherwise, check if keyword is an engine simulation parameter */ if ((k = ihash_lookup(kwdtable, keywd)) >= 0) { if (cfkwd[k].set(sf, value)) return -1; } else if (parse_engine_param(sf, save_keywd, value)) { return -1; } } if (config_close(pconfig)) { ERRMSG(sf, "call to config_close"); return -1; } config_destroy(pconfig); return 0; } /* * parse and set value of engine keyword * return 0 if parsed correctly or if keyword is unrecognized * return -1 (and set error message) if "unrecoverable" MDAPI error */ int parse_engine_param(SimFront *sf, const char *keywd, const char *value) { MD_Sim *sim = sf->sim; MD_Int idnum, typenum; MD_Dvec dvec; MD_Fvec fvec; float ftmp; double dtmp; int itmp; MD_String stmp; MD_Short_String shtmp; char ctmp; if ((idnum = MD_lookup(sim, keywd)) < 0) { warning(sf, "skipping unrecognized keyword \"%s\" " "in configuration file", keywd); return 0; } if ((typenum = MD_getattr(sim, idnum).typenum) == MD_FAIL) { ERRMSG(sf, MD_errmsg(sim)); return -1; } switch (typenum) { case MD_CHAR: sscanf(value, "%c", &ctmp); if (MD_setdata(sim, idnum, &ctmp, 1, 0) || MD_wait(sim)) { ERRMSG(sf, MD_errmsg(sim)); return -1; } break; case MD_SHORT_STRING: sscanf(value, "%7s", shtmp); if (MD_setdata(sim, idnum, &shtmp, 1, 0) || MD_wait(sim)) { ERRMSG(sf, MD_errmsg(sim)); return -1; } break; case MD_STRING: sscanf(value, "%63s", stmp); if (MD_setdata(sim, idnum, &stmp, 1, 0) || MD_wait(sim)) { ERRMSG(sf, MD_errmsg(sim)); return -1; } break; case MD_INT: while (isspace(*value)) value++; /* get rid of leading WS */ if (isdigit(*value)) { sscanf(value, "%d", &itmp); } else { /* convert to Boolean value if "ON", "OFF", "YES", "NO" */ itmp = ( (mdutil_strcasecmp(value,"ON") || mdutil_strcasecmp(value,"YES")) ? 1 : 0 ); } if (MD_setdata(sim, idnum, &itmp, 1, 0) || MD_wait(sim)) { ERRMSG(sf, MD_errmsg(sim)); return -1; } break; case MD_FLOAT: sscanf(value, "%f", &ftmp); if (MD_setdata(sim, idnum, &ftmp, 1, 0) || MD_wait(sim)) { ERRMSG(sf, MD_errmsg(sim)); return -1; } break; case MD_DOUBLE: sscanf(value, "%lf", &dtmp); if (MD_setdata(sim, idnum, &dtmp, 1, 0) || MD_wait(sim)) { ERRMSG(sf, MD_errmsg(sim)); return -1; } break; case MD_FVEC: sscanf(value, "%f %f %f", &fvec.x, &fvec.y, &fvec.z); if (MD_setdata(sim, idnum, &fvec, 1, 0) || MD_wait(sim)) { ERRMSG(sf, MD_errmsg(sim)); return -1; } break; case MD_DVEC: sscanf(value, "%lf %lf %lf", &dvec.x, &dvec.y, &dvec.z); if (MD_setdata(sim, idnum, &dvec, 1, 0) || MD_wait(sim)) { ERRMSG(sf, MD_errmsg(sim)); return -1; } break; default: if (MD_type_name(sim, typenum) == NULL) { ERRMSG(sf, MD_errmsg(sim)); return -1; } warning(sf, "skipping keyword \"%s\" in configuration file,\n" "don't know how to read value of type \"%s\"", keywd, MD_type_name(sim, typenum)); } return 0; } int postprocess_config(SimFront *sf) { int k; if (sf->cwd == NULL) { ERRMSG(sf, "config parameter \"Cwd\" must be specified"); return -1; } if (sf->numsteps < 0) { ERRMSG(sf, "config parameter \"NumSteps\" must be nonnegative"); return -1; } if (sf->coorfile == NULL) { ERRMSG(sf, "config parameter \"Coordinates\" must be specified"); return -1; } if (sf->topofile == NULL) { ERRMSG(sf, "config parameter \"Structure\" must be specified"); return -1; } if (sf->paramfilelistnum == 0) { ERRMSG(sf, "config parameter \"Parameters\" must be specified"); return -1; } if (sf->outputfile == NULL) { ERRMSG(sf, "config parameter \"Output\" must be specified"); return -1; } if (sf->restartfreq != 0 && sf->restartfile == NULL) { ERRMSG(sf, "config parameter \"Restart\" must be specified " "if \"RestartFreq\" is set"); return -1; } if (sf->restartfreq < 0) { ERRMSG(sf, "config parameter \"RestartFreq\" must be nonnegative"); return -1; } if (sf->energyfreq < 0) { ERRMSG(sf, "config parameter \"EnergyFreq\" must be nonnegative"); return -1; } if (sf->temperature < 0.0) { ERRMSG(sf, "config parameter \"Temperature\" must be nonnegative"); return -1; } for (k = 0; k < sf->paramfilelistnum; k++) { if (prepend_cwd(sf, &(sf->paramfilelist[k]))) return -1; } if (prepend_cwd(sf, &(sf->topofile))) return -1; if (prepend_cwd(sf, &(sf->coorfile))) return -1; if (prepend_cwd(sf, &(sf->bincoorfile))) return -1; if (prepend_cwd(sf, &(sf->velfile))) return -1; if (prepend_cwd(sf, &(sf->binvelfile))) return -1; if (prepend_cwd(sf, &(sf->outputfile))) return -1; if (prepend_cwd(sf, &(sf->restartfile))) return -1; return 0; } /* * prepend the current working directory to file if path is relative */ int prepend_cwd(SimFront *sf, char **pfname) { char *oldname; if (*pfname == NULL || **pfname == '/') return 0; oldname = *pfname; *pfname = (char *) malloc(strlen(sf->cwd) + strlen(oldname) + 2); if (*pfname == NULL) { ERRMSG(sf, strerror(errno)); return -1; } strcpy(*pfname, sf->cwd); strcat(*pfname, "/"); strcat(*pfname, oldname); free(oldname); return 0; }