/*
    This file is part of the FElt finite element analysis package.
    Copyright (C) 1993 Jason I. Gobat and Darren C. Atkinson

    This program 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.

    This program 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 this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/****************************************************************************
*
* File:         felt.c
*
* Description:  Contains code for the driver application for the Finite 
*               ELemenT (FELT) package currently under development.
*
* History:     	v1.0 by Jason Gobat and Darren Atkinson 
*
* Notes:        
*
*****************************************************************************/

# include <stdio.h>
# include <string.h>
# include "problem.h"
# include "fe.h"
# include "error.h"

# ifndef LIBDIR
# define LIBDIR "/usr/local/lib/felt"
# endif

static char *usage = "\
usage: felt [options] [filename]\n\
       -debug              write debugging output\n\
       -summary            include material summary statistics\n\
       -printk             print the global stiffness matrix\n\
       -graphics filename  create file for structure visualization\n\
       -nocpp              do not use a preprocessor\n\
       -cpp filename       preprocessor to use\n\
       -Dname[=value]      define a macro\n\
       -Uname              undefine a macro\n\
       -Idirectory         specify include directory\n\
";

static int debug = 0;
static int summary = 0;
static int printk = 0;
static char *graphics = NULL;


/************************************************************************
 * Function:	 CheckSyntax						*
 *									*
 * Parameters:	 argc - number of command line arguments		*
 *		 argv - array of command line arguments			*
 *									*
 * Return value: input file pointer					*
 *									*
 * Calls:	 none							*
 *									*
 * Called by:	 main							*
 *									*
 * Global data:	 the debug flag is modified				*
 *									*
 * Description:	 CheckSyntax checks the syntax of the command line	*
 *		 arguments.  If the syntax is incorrect then a usage	*
 *		 message is written to standard error and the program	*
 *		 is exited.  Otherwise, an attempt is made to open the	*
 *		 specified file on the command line invoking the	*
 *		 specified preprocessor.  If successful, the open file	*
 *		 pointer is returned.					*
 ************************************************************************/

FILE *CheckSyntax (argc, argv)
    int   argc;
    char *argv [ ];
{
    int   i;			/* loop variable	  */
    FILE *input;		/* input file pointer	  */
    char *arg,			/* current argument	  */
	  command [2048],	/* command line		  */
	 *cpp,			/* preprocessor		  */
	  cppargs [2048],	/* preprocessor arguments */
	 *filename;		/* input filename	  */


    /* Initialize. */

    cpp = "/lib/cpp";
    strcpy (cppargs, " -I");
    strcat (cppargs, LIBDIR);
    filename = NULL;


    /* Check each argument. */

    for (i = 1; i < argc; i ++) {
	arg = argv [i];
	if (arg [0] == '-') {
	    if (arg [1] == '\0') {
		filename = NULL;
		continue;
	    } else if (!strcmp (arg, "-help")) {
		fputs (usage, stderr);
		exit (0);
	    } else if (!strcmp (arg, "-debug")) {
		debug = 1;
		continue;
            } else if (!strcmp (arg, "-summary")) {
                summary = 1;
                continue;
            } else if (!strcmp (arg, "-printk")) {
                printk = 1;
                continue;
            } else if (!strcmp (arg, "-graphics")) {
		if (++ i >= argc) {
		    fputs (usage, stderr);
		    exit (1);
		}
                graphics = argv [i];
                continue;
	    } else if (!strcmp (arg, "-nocpp")) {
		cpp = NULL;
		continue;
	    } else if (!strcmp (arg, "-cpp")) {
		if (++ i >= argc) {
		    fputs (usage, stderr);
		    exit (1);
		}
		cpp = argv [i];
		continue;
	    } else if (arg [1] == 'D' || arg [1] == 'U' || arg [1] == 'I') {
		strcat (cppargs, " \"");
		strcat (cppargs, arg);
		strcat (cppargs, "\"");
		continue;
	    } else {
		fputs (usage, stderr);
		exit (1);
	    }
	} else
	    filename = arg;
    }

    if (filename != NULL)
	if (freopen (filename, "r", stdin) == NULL)
	    Fatal ("unable to open %s", filename);

    if (cpp != NULL) {
	strcpy (command, cpp);
	strcat (command, cppargs);
	if ((input = popen (command, "r")) == NULL)
	    Fatal ("unable to execute %s", command);
    } else
	input = stdin;
	

    return input;
}

/************************************************************************
 * Function:	 main							*
 *									*
 * Parameters:	 argc - number of command line arguments		*
 *		 argv - array of command line arguments			*
 *									*
 * Return value: 0 on success; nonzero on error				*
 *									*
 * Calls:	 AssembleStiffness, CheckSyntax, ConstructForceVector,	*
 *		 FindDOFS, GetProblem, SolveForDisplacements, 		*
 *		 ZeroConstraintedDOFS,	SolveForReactions, WriteOutput, *
 *		 WriteGraphicsFile, ZeroFixedDisplacements, Fatal	*
 *									*
 * Called by:	 none							*
 *									*
 * Global data:	 none							*
 *									*
 * Description:	 Main is the driver function for the felt package.	*
 ************************************************************************/

int main (argc, argv)
    int   argc;
    char *argv [ ];
{
    char	*title;			/* title of problem		*/
    FILE	*input;			/* input file pointer		*/
    Element	*element;		/* array of element structures	*/
    Node	*node;			/* array of node structures	*/
    unsigned	 numelts,		/* number of element structures	*/
		 numnodes;		/* number of node structures	*/
    unsigned	 count;			/* number of affected dofs	*/
    Matrix	 K,			/* global stiffness matrix	*/
		 Kcond;			/* condensed stiffness matrix	*/
    Vector	 F,			/* force vector			*/
		 Fcond,			/* condensed force vector	*/
		 d;			/* displacement vector		*/
    unsigned	 dofs [7];		/* degrees of freedom		*/
    int		 status;		/* return status		*/
    Reaction	 *R;			/* reaction force vector	*/
    unsigned	 numreactions;		/* the number of reactions	*/


        /*
         * Do everything
         */

    input = CheckSyntax (argc, argv);

    if (GetProblem (input, &element, &node, &numelts, &numnodes, &title))
	exit (1);

    pclose (input);

    if (numnodes == 0 || numelts == 0) 
       Fatal ("nothing to do");

    if (debug) 
	WriteFeltFile (stdout, element, node, numelts, numnodes, title); 

    if (graphics != NULL) {
       status = WriteGraphicsFile (graphics, element, numelts);
       if (status)
          Fatal ("could not open graphics file for output");
    }

    count = FindDOFS (element, numelts, dofs);

    K = AssembleStiffness (element, numelts, numnodes, count, dofs, &status);

    if (status)
	Fatal ("%d Fatal errors in element stiffness definitions", status);

    if (printk)
       PrintMatrix (K, stdout);

    F = ConstructForceVector (node, numnodes, count, dofs);
    
    ResolveConstraints (K, F, &Kcond, &Fcond, node, numnodes, count, dofs);
     
    d = SolveForDisplacements (Kcond, Fcond, node, numnodes, count, dofs);
    if (d == NullVector)
       exit (1);
    
    status = EltStresses (element, numelts);

    if (status) 
       Fatal ("%d Fatal errors found computing element stresses", status);

    numreactions = SolveForReactions (K, d, node, numnodes, count, dofs, &R);

    WriteOutput (stdout, title, element, node, R, 
                 numelts, numnodes, numreactions, summary);

    exit (0);
}
