/***********************************************************************
Filename: 	read_abaqus.c
Authors:	Eija Achren, Lauri Glad, Pekka Haara, Tuja Rinne, Sarianne Mykra
Date:           16.6.1992

Description:	read_ABAQUS standalone version

                This program translates ABAQUS output file to UCD structure
		which AVS can read.

                This file contain the main function of the read_ABAQUS 
		stand alone version. It also includes the functions needed 
		to read command line parameters. Other files used are read.c
		, construct.c and abaqus.c.

 ***********************************************************************/

#define IS_MAIN 1   /* this file contains the main function */
#define STANDALONE 1


#include "fem.h"
#include "defin.h"

#include <avs/ucd_defs.h>

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#include <stdlib.h>

#define OK 1
#define ERROR -1
#define ERR 0 


/***********************************************************************
 * Global variables. These variables are defined as external variables in the
 * file defin.h for other read_ABAQUS-modules code-files than this
 ***********************************************************************/

bool disp_vec=FALSE;    /* variable for the param. Disp.vector      */
bool disp_x=FALSE;      /* variable for the param. displacement x   */
bool disp_y=FALSE;      /*         -//-            displacement y   */
bool disp_z=FALSE;      /*         -//-            displacement z   */
bool stress_x=FALSE;    /*         -//-               stress x      */
bool stress_y=FALSE;    /*         -//-               stress y      */
bool stress_z=FALSE;    /*         -//-               stress z      */
bool stress_xy=FALSE;   /*         -//-               stress xy     */
bool stress_xz=FALSE;   /*         -//-               stress xz     */
bool stress_yz=FALSE;   /*         -//-               stress yz     */
bool stress_vec=FALSE;  /*         -//-               stress vector */
bool von_Mises=FALSE;   /* variable for the parameter von Mises     */
bool max_shear=FALSE;   /* variable for the parameter max shear     */
bool temperature=FALSE; /* variable for the param. temperature      */

int step_nr=0;          /* variable for the parameter step number   */
int inc_nr=0;           /*           -//-             inc number    */
int shell_elem=0;       /* variable for the parameter shell element */



/**************************************************************
  Functions in other files
---------------------------------------------------------------/


/* in tuija.c : */

extern int read_initial_data(char *filename, AllData *changes, Model *original, STime *inc_time);
extern int read_ABAQUS_data( AllData *changes, int last_step, int last_inc);

/* in eija.c : */

extern int  construct_UCD(UCD_structure **out,Model *original,AllData *changes,char *filename);


/*************************************************************
Function:	error_message

Description:	writes error message to stderr

Input: 		*format:      message format string
                *str1, *str2: variables to be printed in message
		code:         severity of error

Output:		-

Global variables: - 
		
Return: 	OK, if error not fatal

-------------------------------------------------------------*/

int error_message(format,str1,str2,code,inc_time)

 char *format, *str1, *str2;
 int code;
 STime *inc_time; /* no use in standalone version */

{
  char formatted[200];

  strcpy(formatted,format);
  strcat(formatted,"\n");

  if (code == -4 || code == -5) /* don't print the last argument */
    fprintf(stderr,formatted,str1,"");
  else
    fprintf(stderr,formatted,str1,str2);

  if(code != -1) exit(code);

  return OK;
}


/*************************************************************
Function: 	str_to_int

Description:	converts string to positive integer

Input:		*str: string
Output:		-
Global variables: -

Return:		ERROR, if string is not a positive integer
                number, string *str converted to integer

-------------------------------------------------------------*/

int str_to_int(str)
 char *str;

{
  int number=0;

  while(*str)
    {
      if(isdigit(*str)) number=10*number+(*str-'0');
      else return ERROR;
      str++;
    }
  return(number);
} /* end of function str_to_int */


/*************************************************************
Function: 	all_true

Description:	sets all global data components TRUE

Input:		-
Output:		-

Global variables: disp_vector, disp_x, disp_y, disp_z, 
                stress_x, stress_y, stress_z, 
		stress_xy, stress_xz, stress_yz, 
		stress_vec, von_Mises, max_shear, 
		temperature: value set TRUE

Return:         ERR, if some component was allready set TRUE
                OK, otherwise

-------------------------------------------------------------*/

int all_true(void)

{
  if(!disp_vec) disp_vec=TRUE;
  else return ERR;
  if(!disp_x) disp_x=TRUE;
  else return ERR;
  if(!disp_y) disp_y=TRUE;
  else return ERR;
  if(!disp_z) disp_z=TRUE;
  else return ERR;
  if(!stress_x) stress_x=TRUE;
  else return ERR;
  if(!stress_y) stress_y=TRUE;
  else return ERR;
  if(!stress_z) stress_z=TRUE;
  else return ERR;
  if(!stress_xy) stress_xy=TRUE;
  else return ERR;
  if(!stress_xz) stress_xz=TRUE;
  else return ERR;
  if(!stress_yz) stress_yz=TRUE;
  else return ERR;
  if(!stress_vec) stress_vec=TRUE;
  else return ERR;
  if(!von_Mises) von_Mises=TRUE;
  else return ERR;
  if(!max_shear) max_shear=TRUE;
  else return ERR;
  if(!temperature) temperature=TRUE;
  else return ERR;
  return OK;
} /* end of function all_true */


/*************************************************************
Function: 	displacements

Description:	sets data components related with displacements

Input:		*str string
Output:		-

Global variables: disp_vec, disp_x, disp_y, disp_z: value set TRUE,
                if selected in arguments

Return:		ERR, if some data component was allready TRUE
                OK, otherwise;

-------------------------------------------------------------*/

int displacements(str)
 char *str;

{
  while(*str)
  {
    switch(*str)
    {
      case 'a':
              if(disp_vec) return ERR;
	      else disp_vec=TRUE;
	      break;
      case 'x':
	      if(!disp_x) disp_x=TRUE;
	      else return ERR;
	      break;
      case 'y':
	      if(!disp_y) disp_y=TRUE;
	      else return ERR;
	      break;
      case 'z':
	      if(!disp_z) disp_z=TRUE;
	      else return ERR;
	      break;
      default: return ERR;
    } /* switch displacement */
    str++;
  } /* while displacement */
  return OK;
} /* end of function displacements */


/*************************************************************
Function: 	stresses

Description:    sets data components related with stresses

Input:          *str string
Output:         -

Global variables: stress_vec, stress_x, stress_y, 
                stress_xy, stress_xz, stress_yz: value set TRUE, 
		if selected in arguments

Return:		ERROR, if some data component was allready TRUE
                OK, otherwise

-------------------------------------------------------------*/

int stresses(str)
char *str;

{

  while(*str)
  {
    switch(*str)
    {
      case 'a':
              if(stress_vec) return ERR;
	      else stress_vec=TRUE;
	      break;
      case 'x':
	      if(!stress_x) stress_x=TRUE;
	      else return ERR;
	      break;
      case 'y':
	      if(!stress_y) stress_y=TRUE;
	      else return ERR;
	      break;
      case 'z':
	      if(!stress_z) stress_z=TRUE;
	      else return ERR;
	      break;
      case '1':
	      if(!stress_xy) stress_xy=TRUE;
	      else return ERR;
	      break;
      case '2':
	      if(!stress_xz) stress_xz=TRUE;
	      else return ERR;
	      break;
      case '3':
	      if(!stress_yz) stress_yz=TRUE;
	      else return ERR;
	      break;
      case 'v':
	      if(!von_Mises) von_Mises=TRUE;
	      else return ERR;
	      break;
      case 'm':
	      if(!max_shear) max_shear=TRUE;
	      else return ERR;
	      break;
      default: return ERR;
    } /* switch stress*/
    str++;
  } /* while stress */
  return OK;
} /* end of function stresses */


/*************************************************************
Function: 	read_parameters

Description:	reads command line parameters

Input:		argc: number of command line parameters
		*argv[]: command line parameters
		*filename: name of input file

Output:         -

Global variables: shell_elem: shell element layer, value will be given
                step_nr, inc_nr: value will be given

Return:		ERROR, if parameters not valid
                OK, otherwise

-------------------------------------------------------------*/

int read_parameters( argc, argv, filename)
 int argc;
 char *argv[];
 char *filename;

{
  int i;                         /* counter                                       */
  int number;                    /* return value from str_to_int                  */
  char *std_name="$stdin";       /* name for stdin, if no file name given         */
  int arg_nr=1;                  /* number of command line argument to be checked */

  if (argc<4) return ERROR;            /* too few arguments                       */

  if (str_to_int(argv[arg_nr])==ERROR) /* first argument is filename (not number) */
  {
    strcpy(filename,argv[arg_nr]);
    if ((number=str_to_int(argv[++arg_nr]))!=ERROR) step_nr=number;
    else return ERROR;
  }
  else                /* first argument is number => stdin is read insted of file */
  {
    strcpy(filename,std_name);
    step_nr=str_to_int(argv[arg_nr]);
  }

  if ((number=str_to_int(argv[++arg_nr]))!=ERROR) inc_nr=number;
  else return ERROR;

  /* read options */
  for (i=++arg_nr;i<argc;i++)
  {
    if (argv[i][0]!='-') return ERROR;
    switch (argv[i][1])
    {
      case 'a': /* all parameters wanted */
              if(!all_true()) return ERROR;
	      break;
      case 'd': /* displacements */
	      if(!displacements(&argv[i][2])) return ERROR;
	      break;
      case 'l': /* shell element layer */
	      if((number=str_to_int(&argv[i][2]))==ERROR) return ERROR;
	      else shell_elem=number;
	      break;
      case 's': /* stresses */
	      if(!stresses(&argv[i][2])) return ERROR;
	      break;
      case 't': /* temperature */
	      if(temperature) return ERROR;
	      temperature=TRUE;
	      break;
      default: /* not legal option */
	      return ERROR;
    } /* switch  option */
  } /* for every option */

  return OK;
} /* end of function read_parameters */


/*************************************************************
Function: 	write_UCD

Description:	writes UCD-structure to stdout in ASCII-format

Input:          out: pointer to UCD structure
                argc: number of command line arrguments
		argv: command line options
		filename: name of input file
Output:		-

Global variables: step_nr: step nmber
                inc_nr: increment number

Return:		-

-------------------------------------------------------------*/

void write_UCD(out, argc, argv,filename)
 UCD_structure *out;
 int argc;
 char *argv[];
 char *filename;

{
  int i, j, k;              /* counters                                  */
  int data_veclen,name_flag;/* data components for model, are names ints */
  int ncells, cell_veclen;  /* number of elements, data components /elem */
  int nnodes;               /* number of nodes                           */
  int node_veclen;          /* number of data components / node          */
  int util_flag;            /* utility flag, no use here                 */
  float *x, *y, *z;         /* pointers to coordinate arrays             */
  char name[80];            /* name of element                           */
  char element_type[80];    /* element type string, types in cell_str[]  */
  int material_type;        /* material type, currently allways 1        */
  int cell_type, cell_name; /* element type and name                     */
  int mid_edge_flags;       /* does the cell have mid-edge nodes         */
  int *node_list=NULL;      /* array of node numbers in cell             */
  int *components=NULL;     /* components of node data vector            */
  char label[80], unit[80]; /* strings to hold labels and units for data */
  float *data=NULL;         /* pointer to node data                      */
  int ncomp;                /* number of components in data vector       */
  char *char_ptr;           /* pointer to char, used when labes checked  */
  bool empty;               /* is there a label for datacomponent        */
  int offset;               /* offset when data values printed           */

  static int num_nodes[2][8]={
    {1,2,3,4, 4, 5, 6, 8},
    {1,3,6,8,10,13,15,20}};
  char *cell_str[]={"pt","line","tri","quad","tet","pyr","prism","hex"};

  /*---- comment section ----*/
  fprintf(stdout,"# file: %s, step: %d, increment: %d\n", filename, step_nr, inc_nr);
  fprintf(stdout,"# options: ");
  if(strcmp(filename,"$stdin"))
    k=3;
  else k=4;
  for (i=k; i<argc; i++)
    fprintf(stdout,"%s ",argv[i]);
  fprintf(stdout,"\n");
  
  /*---- Header section	-----*/
  UCDstructure_get_header(out, name, &data_veclen, &name_flag,
	    &ncells, &cell_veclen, &nnodes, &node_veclen, &util_flag);
  UCDstructure_get_node_components(out, &components);

  /* # of nodes, cells, nodecomponents, (cell & model components) */
  fprintf(stdout,"%d %d %d 0 0\n", nnodes, ncells, node_veclen);
  
  /*---- Node position section ----*/
  UCDstructure_get_node_positions(out, &x, &y, &z);
  /* node id, x,y,z coordinates					*/
  for(i=0;i<nnodes; i++)
    fprintf(stdout,"%d %f %f %f\n", i, x[i], y[i], z[i]);
  
  /*---- Cell connectivity section ----*/
  /* cell id, (material id), name of the cell type, node id list	*/
  for(i=0; i<ncells; i++)
  {
    UCDcell_get_information(out, i, &cell_name, element_type,
		      &material_type, &cell_type, &mid_edge_flags, &node_list);
    fprintf(stdout,"%d 1 %s ", i, cell_str[cell_type]);
    for(j=0;j<num_nodes[mid_edge_flags][cell_type];j++)
      fprintf(stdout,"%d ", node_list[j]);
    fprintf(stdout,"\n");
  }

  /*---- Data section ----*/
  /* Header: number of components, individual components */
  for (ncomp=0; components[ncomp]!=0; ncomp++);
  fprintf(stdout,"%d ",ncomp);
  for(i=0;i<ncomp;i++)
    fprintf(stdout,"%d ",components[i]);
  fprintf(stdout,"\n");
  /* print labels and units */
  for(i=0;i<ncomp;i++)
  {
    UCDstructure_get_node_label(out, i, label);
    UCDstructure_get_node_unit(out, i, unit);
    /* check if no unit, put unit ? */
    empty=TRUE;
    char_ptr=unit;
    while(*char_ptr!='\0')
    {
      if(*char_ptr!=' ')empty=FALSE;
      char_ptr++;
    }
    if(empty) 
    {
      unit[0]='?';
      unit[1]='\0';
    }
    fprintf(stdout,"%s, %s\n", label, unit); 
  }
  /* data: node id, data vector */
  UCDstructure_get_node_data(out, &data);

  for(i=0;i<nnodes;i++)
  {
    fprintf(stdout,"%d ",i);
    offset=0;
    for(j=0; j<ncomp; j++)
    {
      for (k=0;k<components[j];k++)
	fprintf(stdout,"%f ",data[offset+i*components[j]+k]);
      offset+=nnodes*components[j];
    }
    fprintf(stdout,"\n");
  }
} /* end of function write_UCD */


/*************************************************************
Function: 	print_help

Description:	writes help page to stderr

Input:		-
Output:		-
Global variables: -
Return:		-

-------------------------------------------------------------*/

void print_help(void)
{
  fprintf(stderr,"Usage: read_ABAQUS [infile] step inc [options] [<infile] [>outfile]\n\n");
  fprintf(stderr,"infile  = ABAQUS output file\t");
  fprintf(stderr,"step    = step number\n");
  fprintf(stderr,"inc     = increment number\t");
  fprintf(stderr,"outfile = UCD-structure file\n");
  fprintf(stderr,"options:\n -a = all components\n");
  fprintf(stderr," -d[xyza] = displacements\n");
  fprintf(stderr," 	x = displacement component x\n");
  fprintf(stderr," 	y = displacement component y\n");
  fprintf(stderr," 	z = displacement component z\n");
  fprintf(stderr," 	a = displacement vector (x,y,z)\n");
  fprintf(stderr," -l[nr]   = layer number of shell elements\n");
  fprintf(stderr," -s[xyz123mva] =stresses\n");
  fprintf(stderr,"        x = stress component x\n");
  fprintf(stderr,"        y = stress component y\n");
  fprintf(stderr,"        z = stress component z\n");
  fprintf(stderr,"        1 = stress component xy\n");
  fprintf(stderr,"        2 = stress component xz\n");
  fprintf(stderr,"        3 = stress component yz\n");
  fprintf(stderr,"        m = max shear stress \n");
  fprintf(stderr,"        v = von Mises stress \n");
  fprintf(stderr,"        a = stress vector (x,y,z)\n");
  fprintf(stderr," -t = temperature\n");

} /* end of function print_help */


/*************************************************************
Function: 	main

Description:    

Input:          argc, number of command line parameters
                argv, command line parameters

Output:         -

Return:         ERROR, if errors
                0, if everything ok		

-------------------------------------------------------------*/

main( argc, argv)
 int argc;
 char *argv[];

{
  AllData changes;         /* data values                     */
  Model original;          /* geometry of model               */
  STime inc_time;          /* structure to hold times of incs */
  UCD_structure *out=NULL;     
  bool file_exists;        /* is there a file 'filename'      */
  int fd;                  /* file descriptor                 */
  char filename[80];       /* name of file                    */

  changes.stress.data = NULL;
  changes.stress.nid = NULL;
  changes.von_Mises.data = NULL;
  changes.von_Mises.nid = NULL;
  changes.max_shear.data = NULL;
  changes.max_shear.nid = NULL;
  changes.disp.data = NULL;
  changes.disp.nid = NULL;
  changes.temp.data = NULL;
  changes.temp.nid = NULL;

#ifdef __convex__
  f_init();    /* initialize Fortran I/O */
#endif

  /* read and check parameters */
  if(read_parameters(argc, argv, filename) != ERROR) 
    {
      /* check that the file exists */

      if(strcmp(filename,"$stdin")) /* not reading stdin */
      {
	file_exists = ((fd = open(filename, O_RDONLY, 0)) != -1);
	if(!file_exists)
	{
	  fprintf(stderr,"File %s does not exist or access denied.\n",filename);
	  return ERROR;
	}
	else
	  close(fd); 
      }
      
      /* read initial data */
      if(read_initial_data(filename, &changes, &original, &inc_time)==ERROR)
	return ERROR;

      /* read step/inc requested, no last step or inc => -1  */
      if(read_ABAQUS_data(&changes, -1, -1)==ERROR)
	  return ERROR;

      /* construct UCD structure */
      if(construct_UCD(&out, &original, &changes, filename) == ERROR)
	return ERROR;

      /* write structure */
      write_UCD(out, argc, argv, filename);

    } /* end if parameters OK */
  else /* parameters not OK */
    {
      print_help();
      return ERROR;
    }
  return 0;
} /* end of main */


