/*
DFT++ is a density functional package developed by the research group
of Professor Tomas Arias
Copyright 1996-2003 Sohrab Ismail-Beigi
This file is part of DFT++.
DFT++ is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
DFT++ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DFT++; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Please see the file CREDITS for a list of authors.
For academic users, we request that publications using results obtained with
this software reference
"New algebraic formulation of density functional calculation," by Sohrab Ismail-Beigi
and T.A. Arias, Computer Physics Communications 128:1-2, 1-45 (June 2000).
and, if using the wavelet basis, further reference
"Multiresolution analysis of electronic structure: semicardinal and wavelet bases,"
T.A. Arias, Reviews of Modern Physics 71:1, 267-311 (January 1999).
and
"Robust ab initio calculation of condensed matter: transparent convergence through
semicardinal multiresolution analysis,'' I.P. Daykov, T.A. Arias, and
Torkel D. Engeness, Physical Review Letters, 90:21, 216402 (May 2003).
For your convenience, preprints of the above articles may be obtained from
http://arXiv.org/abs/cond-mat/9909130, 9805262, and 0204411, respectively.
*/
/*
* Contains the parser (and related functions) that reads
* the input file and figures out what it says, checks for errors,
* and issues commands to do what the input files wants.
*
* The parser does not define any commands; that is done in the
* files in the commands/ directory.
*
*/
#include <time.h>
#include "header.h"
#include "commands/command.h"
//
// Special errors from processing go into
// this little buffer
//
char processing_error[DFT_LINE_LEN];
// Print out all the commands and their format
static void
print_commands(command *list)
{
if (list == NULL)
die("\nCan't print a null command list!\n");
command *c = list;
do
{
dft_log("%s\n",c->format);
c = c->next_command;
}
while (c!=NULL);
}
// Read a non-empty, non-comment line from the input file
// and put it into the string s. Up to n-1 chars are read.
// Returns NULL if EOF or some other fgets error is encountered.
static char *
read_a_line(char *s,int n,dft_text_FILE *fp)
{
char key[DFT_MSG_LEN];
while (1)
{
if (dft_text_fgets(s,n,'\\',fp)==NULL)
return NULL;
else if (s[0]=='#' || sscanf(s,"%s",key)<1)
continue;
else
return s;
}
}
// Returns command pointer for command in string str
// or NULL if it can't find it
static command *
find_command(char *str,command *list)
{
command *c = list;
while(c!=NULL)
{
if (strcmp(str,c->name) == 0)
return c;
else
c = c->next_command;
}
return NULL;
}
// Returns command pointer for command number
// or NULL if it can't find it
static command *
find_command(int number,command *list)
{
command *c = list;
while(c!=NULL)
{
if (number == c->number)
return c;
else
c = c->next_command;
}
return NULL;
}
// Go through dependency list of command cmnd
// and check to see if they are satisfied (return 0)
// or return the failed dependency number
static int
check_dependencies(command *cmnd,command *list)
{
int idep,i=0;
while( (idep=cmnd->dependencies[i]) != 0)
{
command *cdep = find_command(abs(idep),list);
if (cdep==NULL)
die("PROBLEM %d %d %s!!!\n",i,idep,cmnd->name);
if ( (idep>0 && !cdep->found) || (idep<0 && cdep->found) )
return idep;
else
i++;
}
return 0;
}
// Print out the status of all found commands with comments and formats
// for those commands preceding them
static void
print_all_command_status(Output *out,command *list,Everything &e)
{
command *c = list;
while (c!=NULL)
{
if (c->found)
{
out->printf("%s\n# %s\n",c->comments,c->format);
c->print_status(e,out);
out->printf("\n");
}
c = c->next_command;
}
out->flush();
}
//
// The parser! (Relatively) short and sweet.
//
void
parse(dft_text_FILE *input_file,Everything &everything)
{
// Create the command list
command *list = create_command_list();
// For now, let's say we have a max of 1000 lines... this
// will be dynamically changed if there are more lines
int max_lines = 200;
command **line_status = (command **)mymalloc(sizeof(command *)*max_lines,
"line_status","parse");
// Count lines, check for command validity, and store
// the command number for that line
char input_line[DFT_LINE_LEN];
int n_lines = 0;
dft_text_rewind(input_file);
while (read_a_line(input_line,DFT_LINE_LEN,input_file) != NULL)
{
char key[DFT_MSG_LEN];
// Is the command recognized?
sscanf(input_line,"%s",key);
command *cmnd = find_command(key,list);
if (cmnd == NULL)
{
dft_log(DFT_SILENCE,"\nValid commands are:\n\n");
print_commands(list);
die("\nCommand '%s' is unknown\n\n",key);
}
// Store the command and increment counter
line_status[n_lines] = cmnd;
n_lines++;
// If we are going to run out of space, get some more!
if (n_lines >= max_lines)
{
max_lines += 100;
line_status = (command **)myrealloc(line_status,
sizeof(command *)*max_lines,
"line_status","parse");
}
}
// Go through all the commands we have and find the
// ones not specified in the input.
// For each such command, if it has a default, do the
// default setup and mark it as found.
// Also, print out the default corresponding command line.
dft_log("\nIssuing the following default commands since they\n");
dft_log("were not explicitely specified.\n\n");
command *cmnd = list;
while(cmnd != NULL)
{
int found=0;
for (int l=0; l < n_lines; l++)
if (cmnd==line_status[l])
found=1;
if (!found && cmnd->has_default)
{
cmnd->set_default(everything);
cmnd->print_status(everything,dft_global_log);
cmnd->found = TRUE;
}
cmnd = cmnd->next_command;
}
dft_log("\n");
// Now we are ready to parse the lines.
// We'll parse the file repeatedly until we're done, or
// we stop because of an error.
// We also assume that we have nothing to do, unless
// we encounter an "overall_action" command.
int nothing_todo = TRUE;
int done = FALSE;
do
{
// Go through the input lines and work on unprocessed lines
dft_text_rewind(input_file);
int n_failed = 0;
int n_succeeded = 0;
int line_counter = 0;
while (read_a_line(input_line,DFT_LINE_LEN,input_file) != NULL)
{
// Get the command corresponding to this line
command *cmnd = line_status[line_counter];
line_counter++;
// If already processed, skip it
if (cmnd == NULL)
continue;
// If you can't use it more than once, die
if(cmnd->found && !cmnd->allow_multiple)
die("\nCommand '%s' can not be used more than once\n\n",
cmnd->name);
// Check the dependencies
int err=check_dependencies(cmnd,list);
if (err!=0)
{
n_failed++;
continue;
}
// Try to process the command
err=cmnd->process_command(input_line,everything);
if (err!=0)
{
n_failed++;
continue;
}
// It succeeded! Mark it found and remove from list
cmnd->found=1;
line_status[line_counter-1]=NULL;
n_succeeded++;
// If this command is an overall activity to be performed,
// then set the flag saying that there is something to do
if (cmnd->is_overall_action)
nothing_todo = FALSE;
} // while (current pass)
// The pass over the input has ended.
// If all the lines we processed failed, we should die.
if (n_failed>0 && n_succeeded==0)
{
dft_log(DFT_SILENCE,"\nConsistency problems:\n\n");
dft_text_rewind(input_file);
line_counter = 0;
while (read_a_line(input_line,DFT_LINE_LEN,input_file) != NULL)
{
command *cmnd = line_status[line_counter];
line_counter++;
if (cmnd == NULL)
continue;
int err=check_dependencies(cmnd,list);
if (err!=0)
{
dft_log(DFT_SILENCE,
"Command '%s' failed because it\n",cmnd->name);
if (err>0)
dft_log(DFT_SILENCE,
"requires command '%s' as well.\n\n\n",
find_command(err,list)->name);
else
dft_log(DFT_SILENCE,
"can not be used simultaneously with '%s'.\n\n\n",
find_command(-err,list)->name);
}
else
{
cmnd->process_command(input_line,everything);
dft_log(DFT_SILENCE,
"Command '%s' had a processing error:\n",
cmnd->name);
dft_log(DFT_SILENCE,"%s",processing_error);
dft_log(DFT_SILENCE,
"Correct command format is:\n%s\n",
cmnd->format);
dft_log(DFT_SILENCE,"The input was:\n%s\n\n\n",input_line);
}
}
die("Exiting.\n\n");
}
// No failures: as long as we have something to do, we're done!
if (n_failed==0)
{
// We sucessfuly parse everything, but were we given
// something to do?
if (nothing_todo)
{
dft_log("\nInput file does not specify an overall activity,\n");
dft_log("so there is nothing to do!\n\n");
dft_log("Issue at least one of the following commands in the input file:\n\n");
command *c=list;
while (c!=NULL)
{
if (c->is_overall_action)
dft_log("%s\n",c->name);
c = c->next_command;
}
die("\nExiting.\n\n");
}
else
done = TRUE;
}
} while (!done);
dft_log("The following is a template of all commands that have been\n");
dft_log("specified in the input file or have been called with\n");
dft_log("automatic defaults.\n");
dft_log("\n>>>>>>>>>>>>>>>>>>Template Begins<<<<<<<<<<<<<<<<<<<<\n\n");
dft_log("# Unit length is the Bohr radius. Energies in Hartrees.\n\n");
print_all_command_status(dft_global_log,list,everything);
dft_log("\n>>>>>>>>>>>>>>>>>>Template Ends<<<<<<<<<<<<<<<<<<<<<<\n\n");
free_command_list(list);
}
//
// Create a command list, execute default setups, and print
// out the resulting template. Useful for when the user wants
// a default template.
//
void
print_default_template(Output *out,Everything &everything)
{
// Create the command list
command *list = create_command_list();
// Go through all the commands and execute default setup
// For those that have it
command *c = list;
while(c != NULL)
{
if (c->has_default)
c->set_default(everything);
c = c->next_command;
}
// Now print out the current status of all commands
out->printf("\n>>>>>>>>>>>>>>>>>>Template Begins<<<<<<<<<<<<<<<<<<<<\n\n");
out->printf("# Unit length is the Bohr radius. Energies in Hartrees\n\n");
c = list;
while (c!=NULL)
{
out->printf("%s\n# %s\n",c->comments,c->format);
if (c->has_default)
c->print_status(everything,out);
out->printf("\n");
c = c->next_command;
}
out->printf("\n>>>>>>>>>>>>>>>>>>Template Ends<<<<<<<<<<<<<<<<<<<<<<\n\n");
out->flush();
// Free command list
free_command_list(list);
}
syntax highlighted by Code2HTML, v. 0.9.1