/* ** Program: nasfranc.c ** ** Purpose: read a NASTRAN input file and translate the file data to ** FRANC2D single layer input file format. ** ** Supported NASTRAN Record Types: ** { "GRID", 4, REC_GRID }, { "CQUAD4", 6, REC_CQUAD4 }, { "CTRIA3", 6, REC_CTRIA3 }, { "CQUAD8", 6, REC_CQUAD8 }, { "CTRIA6", 6, REC_CTRIA6 }, { "MAT1", 4, REC_MAT1 }, { "MAT8", 4, REC_MAT8 }, { "FORCE", 5, REC_FORCE }, { "SPC1", 4, REC_SPC1 }, { "SPC", 3, REC_SPC }, { "PSHELL", 6, REC_PSHELL }, { "TITLE", 5, REC_TITLE }, { "BEGIN BULK", 10, REC_BULK }, { "ENDDATA", 7, REC_ENDDATA }, ** ** To add new record types or modify existing types look at the ** ReadNASTRAN() routine and work through the thread of execution. ** ** Programmer: Mark James ** Date: January 1998 ** Version: 1.0 ** */ #include #include #include /********************************************************************** ** Memory handling macros */ #define Malloc( num, type ) ((type*)calloc(num,sizeof(type))) #define Free( ptr ) if ( ptr ) { free( ptr ) ; ptr = 0 ; } /********************************************************************** ** SYMBOLIC CONSTANTS */ #define LEN 1024 #define NUMNODES 8 /* Number of nodes for each element */ #define NUM_MAT_PROPS 12 #define PlaneStress 1 #define QUANTUM 1000 /* franc values for load_types[] */ #define TYP_NONE 1 #define TYP_NODAL 2 #define TYP_APPDISP 8 /* franc material types and indeces */ #define MAT_ISO 1 #define MAT_ORTHO 2 enum { MAT_ISO_E = 0, MAT_ISO_NU, MAT_ISO_THK, MAT_ISO_KIC, MAT_ISO_RHO }; enum { MAT_ORTHO_E1 = 0, MAT_ORTHO_E2, MAT_ORTHO_E3, MAT_ORTHO_G12, MAT_ORTHO_NU12, MAT_ORTHO_NU13, MAT_ORTHO_NU23, MAT_ORTHO_BETA, MAT_ORTHO_THK, MAT_ORTHO_KIC1, MAT_ORTHO_KIC2, MAT_ORTHO_RHO }; /********************************************************************** ** STRUCTURES */ typedef struct { int id ; int node[NUMNODES] ; /* Nodes for each T6 or Q8 */ int material ; int num_nodes ; int num_added ; } Element ; typedef struct { int id ; double x ; /* X coordinate of node */ double y ; /* Y coordinate of node */ } Node ; typedef struct { int id; int type; double props[NUM_MAT_PROPS]; } Material ; typedef struct { int set; int node; double x, y; } Force ; /* components of fixity and applied displacements */ #define FIX_X 1 #define FIX_Y 2 #define APP_X 3 #define APP_Y 4 typedef struct { int id ; int component; int node; double value; } Fixity ; typedef struct { int id ; int mat ; double thickness; } Property; /********************************************************************** ** GLOBAL VARIABLES */ char purpose[] = "Purpose: This program reads NASTRAN mesh files and translates to FRANC2D\n" " input file format.\n\n"; char usage[] = "Usage:\n" " nasfranc: [-debug] [-onemat] [-meshonly] [nas_file] [franc_file]\n\n"; int numel, numnp, nummat, numforce, numfixity, numapp, numprop ; int max_el, max_np, max_force, max_fixity; #define MAX_MAT 15 /* limit defined by FRANC2D */ #define MAX_CASE 6 /* limit defined by FRANC2D */ #define MAX_TITLE 80 /* franc will only read the first 40 chars */ Element *elem ; /* Pointer to element data */ Node *node ; /* Pointer to node data */ Force *force ; Fixity *fixity ; Material mat[MAX_MAT] ; Property prop[MAX_MAT]; /* NASTRAN property sheet for shell */ Material aluminum = { 1, 1, 10000.0, 0.3, 1.0, 1.0, 1.0 } ; char in_fname[LEN] ; /* must be dimensioned by LEN */ char out_fname[LEN] ; char problem_title[LEN]; /* title read from the input file */ int probtype = 1; /* default is plane stress */ int load_types[] = { TYP_NONE, TYP_NONE, TYP_NONE, TYP_NONE, TYP_NONE, TYP_NONE } ; int load_swap[] = { 1, 2, 3, 4, 5, 6 } ; /* Command line options */ int debug = 0; int onemat = 0; int meshonly = 0; int overwrite = 0; /********************************************************************** ** File handling and storage allocation routines */ void GetFiles( in_fname, out_fname ) char *in_fname ; char *out_fname ; { FILE *fp ; /* check if the input file was specified */ if (strlen(in_fname) == 0) { printf("\nEnter name of input file: ") ; fflush(stdout) ; if ( fgets( in_fname, LEN, stdin ) == NULL ) { fprintf(stderr, "*** Error reading file name **\n" ) ; exit(1) ; } strtok( in_fname, "\n" ) ; /* strip the newline character */ } /* check if the output file was specified */ if (strlen(out_fname) == 0) { printf("Enter name of output file: ") ; fflush(stdout) ; if ( fgets( out_fname, LEN, stdin ) == NULL ) { fprintf(stderr, "*** Error reading file name **\n" ) ; exit(1) ; } strtok( out_fname, "\n" ) ; /* strip the newline character */ } /* Check if the output file exists, and if so, do we overwrite */ if (overwrite == 0) { fp = fopen(out_fname, "r") ; if( fp ) { char line[LEN]; fprintf(stderr,"Output file exists: \"%s\"\n", out_fname ); for(;;) { printf("Overwrite file (y,n): " ) ; fflush(stdout) ; fgets(line, LEN, stdin) ; if ( line[0] == 'y' || line[0] == 'Y' ) { break ; } else if ( line[0] == 'n' || line[0] == 'N' ) { printf("Cancelling conversion!\n") ; exit(1) ; } } fclose(fp); } } if (debug) { fprintf(stderr,"\nInput file \"%s\"\n", in_fname); } if (debug) { fprintf(stderr,"Output file \"%s\"\n\n", out_fname); } } FILE *OpenFile( fname, mode ) char* fname ; char* mode ; { FILE *fp ; fp = fopen(fname, mode) ; if( fp == NULL ) { fprintf(stderr,"*** Problems opening file: \"%s\" ***\n", fname) ; exit(1) ; } return fp ; } void GetStorage() { /* check the number of elements */ if (numel >= max_el) { int i ; Element *tmp = elem; while( numel >= max_el ) { max_el += QUANTUM; } elem = Malloc( max_el, Element) ; if( elem == NULL ) { printf("Unable to allocate memory for element storage.") ; exit(1) ; } if (tmp) { /* copy the data to the new array */ for( i = 0 ; i < numel ; ++i ) { elem[i] = tmp[i]; } Free(tmp); } } /* check the number of nodes */ if (numnp >= max_np) { int i ; Node *tmp = node; while( numnp >= max_np ) { max_np += QUANTUM; } node = Malloc( max_np, Node) ; if( node == NULL ) { printf("Unable to allocate memory for node storage.") ; exit(1) ; } if (tmp) { /* copy the data to the new array */ for( i = 0 ; i < numnp ; ++i ) { node[i] = tmp[i]; } Free(tmp); } } /* check the number of forces */ if (numforce >= max_force) { int i ; Force *tmp = force; while( numforce >= max_force ) { max_force += QUANTUM; } force = Malloc( max_force, Force) ; if( force == NULL ) { printf("Unable to allocate memory for force storage.") ; exit(1) ; } if (tmp) { /* copy the data to the new array */ for( i = 0 ; i < numforce ; ++i ) { force[i] = tmp[i]; } Free(tmp); } } /* check the number of fixity */ if (numfixity >= max_fixity) { int i ; Fixity *tmp = fixity; while( numfixity >= max_fixity ) { max_fixity += QUANTUM; } fixity = Malloc( max_fixity, Fixity) ; if( fixity == NULL ) { printf("Unable to allocate memory for fixity storage.") ; exit(1) ; } if (tmp) { /* copy the data to the new array */ for( i = 0 ; i < numfixity ; ++i ) { fixity[i] = tmp[i]; } Free(tmp); } } } /********************************************************************** ** Routines and data for reading the NASTRAN file. */ /* Field separator for format free records */ #define REC_FLDSEP ',' #define REC_TITLESEP '=' /* Some constants defining the records */ #define REC_FIELDS 10 /* number of 8 character fields */ #define REC_LOW 0X00FFFF /* low short is the type */ #define REC_HIGH 0xFF0000 /* high short is flags */ #define REC_DOUBLE 0x010000 /* flag for double sized fields */ #define REC_FMTFREE 0x020000 /* flag for format free fields */ /* Enumerated record types */ enum { REC_UNKNOWN = 0, REC_GRID, REC_CQUAD4, REC_CTRIA3, REC_CQUAD8, REC_CTRIA6, REC_MAT1, REC_MAT8, REC_FORCE, REC_SPC, REC_SPC1, REC_PSHELL, REC_CONTINUE, REC_TITLE, REC_BULK, REC_ENDDATA }; /* Some constants for fields within records */ #define FLD_STANDARD 8 /* standard width field is 8 characters */ #define FLD_DOUBLE 16 /* double width field is 16 characters */ typedef struct { char *label ; /* character name of the rec type */ int len ; /* number of characters in name */ int type ; /* enumerated type */ } RecType ; RecType types[] = { { "GRID", 4, REC_GRID }, { "CQUAD4", 6, REC_CQUAD4 }, { "CTRIA3", 6, REC_CTRIA3 }, { "CQUAD8", 6, REC_CQUAD8 }, { "CTRIA6", 6, REC_CTRIA6 }, { "MAT1", 4, REC_MAT1 }, { "MAT8", 4, REC_MAT8 }, { "FORCE", 5, REC_FORCE }, { "SPC1", 4, REC_SPC1 }, /* must be before SPC */ { "SPC", 3, REC_SPC }, { "PSHELL", 6, REC_PSHELL }, { "TITLE", 5, REC_TITLE }, { "BEGIN BULK", 10, REC_BULK }, { "ENDDATA", 7, REC_ENDDATA }, }; #define MAX_FIELDS 50 #define MAX_FIELD_LEN LEN typedef struct { char data[MAX_FIELDS][MAX_FIELD_LEN] ; int num_fields ; int max_fields ; int type ; } Record ; #define NumStruct(str) (sizeof(str)/sizeof(str[0])) #define FMT_UNKNOWN -1 #define FMT_FREE 1 #define FMT_FORMATTED 2 #define FMT_DOUBLE 3 #define FMT_SINGLE 4 int file_format = FMT_UNKNOWN; /* look at the first few characters of a line for the record type */ RecType* GetRecType( line ) char *line ; { int num = NumStruct(types); int i; for( i = 0 ; i < num ; ++i ) { if (strncmp(line,types[i].label,types[i].len) == 0) { return &types[i] ; } } return NULL; /* error return value */ } /* if there is an asterisk in the record, assume double precision */ int CheckRecDouble(line) char *line ; { if (strchr(line,'*') != NULL) { return FMT_DOUBLE; } return FMT_SINGLE; } /* if there is a comma in the record, assume free format */ int CheckRecFormat(line) char *line ; { if (strchr(line,REC_FLDSEP) != NULL) { return FMT_FREE; } return FMT_FORMATTED; } /* sort of like strtok(), but does not collapse multiple delimiters ** into one field. Also assumes one character in sep. */ char *Index(s,sep) char *s; char *sep; { static char *curr; if (s) { if (curr = strchr(s,*sep)) { *curr = '\0'; } } else { if (curr) { s = ++curr; curr = strchr(curr,*sep); if (curr) { *curr = '\0'; } } else { return NULL; } } return s; } /* copy data from the line into a parsed record structure */ void CpyFields( line, type, rec ) char *line ; int type; Record *rec; { /* assume that all data in the file have the same format (either ** formatted or format free). */ if (file_format == FMT_UNKNOWN) { file_format = CheckRecFormat(line); } if (file_format == FMT_FREE) { char seps[] = ","; char tmp[LEN]; char *token; strcpy(tmp,line); /* get the first token (field) in the line */ //token = strtok(tmp,seps); token = Index(tmp,seps); /* if this is a continuation line, throw out the first */ if (type == REC_CONTINUE) { --rec->num_fields ; //token = strtok(NULL,seps); token = Index(NULL,seps); } else { rec->type = type; } /* While there are tokens in the line */ while( token != NULL ) { strncpy(rec->data[rec->num_fields],token,MAX_FIELD_LEN); rec->data[rec->num_fields++][MAX_FIELD_LEN-1] = '\0'; //token = strtok(NULL,seps); /* Get next token: */ token = Index(NULL,seps); } } else { int i; char *first; int start = 0; int num = REC_FIELDS; int len = FLD_STANDARD; /* check if the record is double precision */ if (CheckRecDouble(line) == FMT_DOUBLE) { len = FLD_DOUBLE; num = REC_FIELDS / 2 + 1; } /* skip over the first field if a continuation record */ if (type == REC_CONTINUE) { --rec->num_fields ; ++start; } else { rec->type = type; } /* loop over the fields and extract the character data */ for( i = start ; i < num ; ++i ) { if (i == 0) { /* first field is always 8 characters */ strncpy(rec->data[rec->num_fields], line, FLD_STANDARD ) ; rec->data[rec->num_fields++][FLD_STANDARD] = '\0'; } else if (i == (num-1)) { /* last field is always 8 characters */ first = line + FLD_STANDARD + (i-1)*len; strncpy(rec->data[rec->num_fields], first, FLD_STANDARD ) ; rec->data[rec->num_fields++][FLD_STANDARD] = '\0'; } else { first = line + FLD_STANDARD + (i-1)*len; strncpy(rec->data[rec->num_fields], first, len ) ; rec->data[rec->num_fields++][len] = '\0'; } } } } /* continuation check: if the final field of the prev line ** matches with the beginning of the current line. Note ** that we start the check at the second character because of the ** possible double precision marker '*' */ int ContCheck( line, rec ) char *line; Record *rec; { int i; char *tmp = rec->data[rec->num_fields-1]; ++tmp; /* start the check at the second character */ ++line; for( i = 0 ; *line == *tmp ; ++i ) { ++line, ++tmp; } return i; } /* read one record (may consist of several lines). The strategy is ** to read lines until the current line is *not* a continuation line. ** Then that line is available in the static variable the next time ** we enter the routine. */ int ReadRecord( fp, rec ) FILE *fp ; Record *rec; { /* static to hold previous unprocessed line */ static char line[LEN]; int num_fields = 0; int rec_type ; int lines ; RecType *type_ptr; /* loop over several lines to build a complete input record */ for(lines = 1 ;; ++lines) { if ( line[0] == 0 ) { /* first time only */ if (fgets(line, LEN, fp) == NULL) { fprintf(stderr,"*** trouble reading input ***\n"); exit(1); } strtok( line, "\n" ) ; /* strip the newline character */ } type_ptr = GetRecType(line) ; /* default record type is from the record data structure */ rec_type = ( type_ptr ? type_ptr->type : REC_UNKNOWN ) ; /* process unknown record types, including continuations, so * that we can get back on track with the next known type */ if (lines > 1) { /* check if this is a continuation line */ if (ContCheck(line,rec) > 0) { CpyFields(line, REC_CONTINUE, rec); } else { return lines-1; } } else { CpyFields(line, rec_type, rec); } if (fgets(line, LEN, fp) == NULL) { break; /* end of file */ } strtok( line, "\n" ) ; /* strip the newline character */ } return -1; /* end of file */ } /********************************************************************** ** Routines and data for Processing records. Note that the fields are ** numbered assuming that the continuation fields don't exist. */ /* GRID */ #define GRID_ID 1 #define GRID_X 3 #define GRID_Y 4 #define GRID_CD 8 int ProcessGRID( rec ) Record *rec; { int id = atoi(rec->data[GRID_ID]); //numnp = max(numnp,id); GetStorage(); node[numnp].id = id; node[numnp].x = atof(rec->data[GRID_X]); node[numnp].y = atof(rec->data[GRID_Y]); if (atoi(rec->data[GRID_CD]) != 0) { fprintf(stderr,"Note: node (%d) ignored alternate system (%d)\n", id, atoi(rec->data[GRID_CD]) ); } ++numnp; return 1; } /* CQUAD4 */ #define CQUAD4_EID 1 #define CQUAD4_PID 2 #define CQUAD4_G1 3 #define CQUAD4_G2 4 #define CQUAD4_G3 5 #define CQUAD4_G4 6 int ProcessCQUAD4( rec ) Record *rec; { int id = atoi(rec->data[CQUAD4_EID]); //numel = max(numel,id); GetStorage(); elem[numel].id = id; elem[numel].node[0] = atoi(rec->data[CQUAD4_G1]); elem[numel].node[1] = atoi(rec->data[CQUAD4_G2]); elem[numel].node[2] = atoi(rec->data[CQUAD4_G3]); elem[numel].node[3] = atoi(rec->data[CQUAD4_G4]); elem[numel].material = atoi(rec->data[CQUAD4_PID]); ++numel; return 1; } /* CTRI3 */ #define CTRI3_EID 1 #define CTRI3_PID 2 #define CTRI3_G1 3 #define CTRI3_G2 4 #define CTRI3_G3 5 int ProcessCTRI3( rec ) Record *rec; { int id = atoi(rec->data[CTRI3_EID]); //numel = max(numel,id); GetStorage(); elem[numel].id = id; elem[numel].node[0] = atoi(rec->data[CTRI3_G1]); elem[numel].node[1] = atoi(rec->data[CTRI3_G2]); elem[numel].node[2] = atoi(rec->data[CTRI3_G3]); elem[numel].material = atoi(rec->data[CTRI3_PID]); ++numel; return 1; } /* CQUAD8 */ #define CQUAD8_EID 1 #define CQUAD8_PID 2 #define CQUAD8_G1 3 #define CQUAD8_G2 4 #define CQUAD8_G3 5 #define CQUAD8_G4 6 #define CQUAD8_G5 7 #define CQUAD8_G6 8 #define CQUAD8_G7 9 #define CQUAD8_G8 10 int ProcessCQUAD8( rec ) Record *rec; { int id = atoi(rec->data[CQUAD8_EID]); //numel = max(numel,id); GetStorage(); elem[numel].id = id; elem[numel].node[0] = atoi(rec->data[CQUAD8_G1]); elem[numel].node[1] = atoi(rec->data[CQUAD8_G5]); elem[numel].node[2] = atoi(rec->data[CQUAD8_G2]); elem[numel].node[3] = atoi(rec->data[CQUAD8_G6]); elem[numel].node[4] = atoi(rec->data[CQUAD8_G3]); elem[numel].node[5] = atoi(rec->data[CQUAD8_G7]); elem[numel].node[6] = atoi(rec->data[CQUAD8_G4]); elem[numel].node[7] = atoi(rec->data[CQUAD8_G8]); elem[numel].material = atoi(rec->data[CQUAD8_PID]); ++numel; return 1; } /* CTRI6 */ #define CTRI6_EID 1 #define CTRI6_PID 2 #define CTRI6_G1 3 #define CTRI6_G2 4 #define CTRI6_G3 5 #define CTRI6_G4 6 #define CTRI6_G5 7 #define CTRI6_G6 8 int ProcessCTRI6( rec ) Record *rec; { int id = atoi(rec->data[CTRI6_EID]); //numel = max(numel,id); GetStorage(); elem[numel].id = id; elem[numel].node[0] = atoi(rec->data[CTRI6_G1]); elem[numel].node[1] = atoi(rec->data[CTRI6_G4]); elem[numel].node[2] = atoi(rec->data[CTRI6_G2]); elem[numel].node[3] = atoi(rec->data[CTRI6_G5]); elem[numel].node[4] = atoi(rec->data[CTRI6_G3]); elem[numel].node[5] = atoi(rec->data[CTRI6_G6]); elem[numel].material = atoi(rec->data[CTRI6_PID]); ++numel; return 1; } /* MAT1 */ #define MAT1_MID 1 #define MAT1_E 2 #define MAT1_G 3 #define MAT1_NU 4 #define MAT1_RHO 5 int ProcessMAT1( rec ) Record *rec; { int id = atoi(rec->data[MAT1_MID]); if (onemat) return 1; if (id > MAX_MAT) { fprintf(stderr, "Material id (%d) > max (%d)\n", id, MAX_MAT); return 0; } nummat = max(nummat,id); //GetStorage(); mat[id-1].id = id; mat[id-1].type = MAT_ISO ; /* linear elastic isotropic */ mat[id-1].props[MAT_ISO_E] = atof(rec->data[MAT1_E]); mat[id-1].props[MAT_ISO_NU] = atof(rec->data[MAT1_NU]); mat[id-1].props[MAT_ISO_THK] = 1.0; mat[id-1].props[MAT_ISO_KIC] = 1.0; mat[id-1].props[MAT_ISO_RHO] = atof(rec->data[MAT1_RHO]); return 1; } /* MAT8 */ #define MAT8_MID 1 #define MAT8_E1 2 #define MAT8_E2 3 #define MAT8_NU12 4 #define MAT8_G12 5 #define MAT8_G13 6 #define MAT8_G23 7 #define MAT8_RHO 8 int ProcessMAT8( rec ) Record *rec; { int id = atoi(rec->data[MAT8_MID]); if (onemat) return 1; if (id > MAX_MAT) { fprintf(stderr, "Material id (%d) > max (%d)\n", id, MAX_MAT); return 0; } nummat = max(nummat,id); //GetStorage(); mat[id-1].id = id; mat[id-1].type = MAT_ORTHO ; /* linear elastic orthotropic */ mat[id-1].props[MAT_ORTHO_E1] = atof(rec->data[MAT8_E1]); mat[id-1].props[MAT_ORTHO_E2] = atof(rec->data[MAT8_E2]); mat[id-1].props[MAT_ORTHO_E3] = 0.0; mat[id-1].props[MAT_ORTHO_G12] = atof(rec->data[MAT8_G12]); mat[id-1].props[MAT_ORTHO_NU12] = atof(rec->data[MAT8_NU12]); mat[id-1].props[MAT_ORTHO_NU13] = 0.0; mat[id-1].props[MAT_ORTHO_NU23] = 0.0; mat[id-1].props[MAT_ORTHO_BETA] = 0.0; mat[id-1].props[MAT_ORTHO_THK] = 1.0; mat[id-1].props[MAT_ORTHO_KIC1] = 1.0; mat[id-1].props[MAT_ORTHO_KIC2] = 1.0; mat[id-1].props[MAT_ORTHO_RHO] = atof(rec->data[MAT8_RHO]); return 1; } /* FORCE */ #define FORCE_SID 1 #define FORCE_G 2 #define FORCE_CID 3 #define FORCE_SCALE 4 #define FORCE_X 5 #define FORCE_Y 6 int ProcessFORCE( rec ) Record *rec; { int id = atoi(rec->data[FORCE_SID]); int cid = atoi(rec->data[FORCE_CID]); double scale = atof(rec->data[FORCE_SCALE]); if (meshonly) return 1; /* skewed coordinate systems are not allowed */ if (cid != 0) { fprintf(stderr, "Ignoring force id (%d) with an alternate coordinate system (%d)\n", id, cid); return 0; } GetStorage(); force[numforce].set = id; force[numforce].node = atoi(rec->data[FORCE_G]); force[numforce].x = atof(rec->data[FORCE_X]) * scale; force[numforce].y = atof(rec->data[FORCE_Y]) * scale; ++numforce ; return 1; } /* SPC */ #define SPC_SID 1 #define SPC_G1 2 #define SPC_C1 3 #define SPC_D1 4 #define SPC_G2 5 #define SPC_C2 6 #define SPC_D2 7 int ProcessSPC( rec ) Record *rec; { int id = atoi(rec->data[SPC_SID]); int i; if (meshonly) return 1; /* supposedly, there can be up to 12 of these. We'll assume ** that the node will be zero at the end */ for( i = 0 ; i < 12 ; i+=3 ) { int node = atoi(rec->data[SPC_G1+i]); char *comp = rec->data[SPC_C1+i]; double value = atof(rec->data[SPC_D1+i]); if (node == 0) { return 1; } /* Now process the components. We'll process each of the ** embedded components separately in franc2dl */ while( *comp != '\0' && *comp == ' ' ) { ++comp; } while( *comp != '\0' ) { GetStorage(); if (*comp == '1' && value == 0.0) { fixity[numfixity].component = FIX_X; } else if (*comp == '2' && value == 0.0) { fixity[numfixity].component = FIX_Y; } else if (*comp == '1') { fixity[numfixity].component = APP_X; } else if (*comp == '2') { fixity[numfixity].component = APP_Y; } else if (*comp == '3') { fprintf(stderr, "Ignore fixity id (%d) component (%c)\n", id, *comp ); return 0; } else if (*comp != ' ') { fprintf(stderr, "Fixity id (%d) had bad component (%c)\n", id, *comp ); return 0; } if (fixity[numfixity].component > 0) { fixity[numfixity].id = id; fixity[numfixity].node = node; fixity[numfixity].value = value; ++numfixity ; } ++comp; } } return 1; } /* SPC1 */ #define SPC1_SID 1 #define SPC1_C 2 #define SPC1_G1 3 #define SPC1_THRU 4 #define SPC1_G2 5 int ProcessSPC1( rec ) Record *rec; { int id = atoi(rec->data[SPC1_SID]); if (meshonly) return 1; /* check for alternate form of the record first */ if (strncmp("THRU",rec->data[SPC1_THRU],4) == 0) { int start = atoi(rec->data[SPC1_G1]); int end = atoi(rec->data[SPC1_G2]); int node; for( node = start; node <= end ; ++node ) { char *comp = rec->data[SPC1_C]; double value = 0.0; /* Now process the components. We'll process each of the ** embedded components separately in franc2dl */ while( *comp != '\0' && *comp == ' ' ) { ++comp; } while( *comp != '\0' ) { GetStorage(); if (*comp == '1') { fixity[numfixity].component = FIX_X; } else if (*comp == '2') { fixity[numfixity].component = FIX_Y; } else if (*comp == '3') { fprintf(stderr, "Ignore fixity id (%d) component (%c)\n", id, *comp ); return 0; } else if (*comp != ' ') { fprintf(stderr, "Fixity id (%d) had bad component (%c)\n", id, *comp ); return 0; } if (fixity[numfixity].component > 0) { fixity[numfixity].id = id; fixity[numfixity].node = node; fixity[numfixity].value = value; ++numfixity ; } ++comp; } } } else { int i; /* there can be many of these. We'll assume ** that the node will be zero at the end */ for( i = SPC1_G1 ; i < rec->num_fields ; ++i ) { int node = atoi(rec->data[i]); char *comp = rec->data[SPC1_C]; double value = 0.0; if (node == 0) { return 1; } /* Now process the components. We'll process each of the ** embedded components separately in franc2dl */ while( *comp != '\0' && *comp == ' ' ) { ++comp; } while( *comp != '\0' ) { GetStorage(); if (*comp == '1') { fixity[numfixity].component = FIX_X; } else if (*comp == '2') { fixity[numfixity].component = FIX_Y; } else if (*comp != ' ') { fprintf(stderr, "Fixity id (%d) had bad component (%d)\n", id, comp ); return 0; } if (fixity[numfixity].component > 0) { fixity[numfixity].id = id; fixity[numfixity].node = node; fixity[numfixity].value = value; ++numfixity ; } ++comp; } } } return 1; } /* PSHELL */ #define PSHELL_PID 1 #define PSHELL_MID 2 #define PSHELL_THICK 3 int ProcessPSHELL( rec ) Record *rec; { int id = atoi(rec->data[PSHELL_PID]); if (onemat) return 1; if (id > MAX_MAT) { fprintf(stderr, "Property id (%d) > max (%d)\n", id, MAX_MAT); return 0; } //numprop = max(numprop,id); //GetStorage(); prop[numprop].id = id; prop[numprop].mat = atoi(rec->data[PSHELL_MID]) ; prop[numprop].thickness = atof(rec->data[PSHELL_THICK]); if (prop[numprop].mat > MAX_MAT) { fprintf(stderr, "Material id (%d) > max (%d) for property (%d)\n", prop[numprop].mat, MAX_MAT, id); return 0; } ++numprop; return 1; } /* read a NASTRAN file and process the data */ void ReadNASTRAN( fp ) FILE *fp ; { int enddata = 0; Record rec ; /* first read the title and throw out junk records at the top ** of the file */ for(;;) { char line[LEN]; RecType *type_ptr; if (fgets(line, LEN, fp) == NULL) { fprintf(stderr,"*** trouble reading input ***\n"); exit(1); } strtok( line, "\n" ) ; /* strip the newline character */ type_ptr = GetRecType(line) ; if (type_ptr) { if (type_ptr->type == REC_TITLE) { char *start = strchr(line,REC_TITLESEP) ; if (start) { ++start; ++start; /* skip forward to title */ strncpy(problem_title,start,MAX_TITLE-1); problem_title[MAX_TITLE] = '\0'; } } else if (type_ptr->type == REC_BULK) { break; } } } /* now process the bulk data */ rec.max_fields = MAX_FIELDS; rec.num_fields = 0; while( (ReadRecord(fp,&rec) > 0) && (enddata == 0) ) { int i; switch(rec.type) { case REC_GRID: ProcessGRID(&rec); break; case REC_CQUAD4: ProcessCQUAD4(&rec); break; case REC_CTRIA3: ProcessCTRI3(&rec); break; case REC_CQUAD8: ProcessCQUAD8(&rec); break; case REC_CTRIA6: ProcessCTRI6(&rec); break; case REC_MAT1: ProcessMAT1(&rec); break; case REC_MAT8: ProcessMAT8(&rec); break; case REC_FORCE: ProcessFORCE(&rec); break; case REC_PSHELL: ProcessPSHELL(&rec); break; case REC_SPC1: ProcessSPC1(&rec); break; case REC_SPC: ProcessSPC(&rec); break; case REC_ENDDATA: enddata = 1; break; default: if (debug) { fprintf(stderr,"Ignore record: \"%s\"\n", rec.data[0]); } } /* clear all of the data */ rec.num_fields = 0; for( i = 0 ; i < rec.max_fields ; ++i ) { rec.data[i][0] = 0; } } } /********************************************************************** ** Routines for processing the data and preparing for output. */ int CountNodes( e ) int e ; { int i, num ; for( num = i = 0 ; i < NUMNODES ; ++i ) { if ( elem[e].node[i] != 0 ) ++num ; } return num ; } void CheckInputData() { int e ; int numquad = 0; int numlin = 0; /* process some command line overrides */ if (onemat) { nummat = 1; mat[0] = aluminum; } if (meshonly) { numfixity = 0; numforce = 0; } /* First check the material data */ for( e = 0 ; e < nummat ; ++e ) { /* the material numbers must be contiguous */ if (mat[e].id != e+1) { fprintf(stderr, "ERROR - invalid material number: %d %d\n", mat[e].id, e+1 ); } } /* Now check the property data */ for( e = 0 ; e < numprop ; ++e ) { /* the property numbers must be contiguous */ if (prop[e].id != e+1) { fprintf(stderr, "ERROR - invalid property number: %d %d\n", prop[e].id, e+1 ); } /* the material referenced must be ok */ if (mat[prop[e].mat-1].id == 0) { fprintf(stderr, "ERROR - invalid material (%d) for property (%d)\n", prop[e].mat, e+1 ); } } /* Update the material thickness; from the property sheet */ for( e = 0 ; e < nummat ; ++e ) { int p; for( p = 0 ; p < numprop ; ++p ) { if (mat[e].id == prop[p].mat) { if (mat[e].type == MAT_ISO) { mat[e].props[MAT_ISO_THK] = prop[p].thickness; } else if (mat[e].type == MAT_ORTHO) { mat[e].props[MAT_ORTHO_THK] = prop[p].thickness; } else { fprintf(stderr,"ERROR - bad material type (%d) " "for material (%d)\n", mat[e].type, mat[e].id); } } } } /* Now check the element data */ for( e = 0 ; e < numel ; ++e ) { int n = CountNodes( e ) ; if ( n != 3 && n != 4 && n != 6 && n != 8) { fprintf(stderr, "ERROR - invalid number of nodes: %d", n ) ; fprintf(stderr, " for element: %d\n", e+1 ) ; exit(1) ; } if (n == 3 || n == 4) { ++numlin; } else if (n == 6 || n == 8) { ++numquad; } /* set the initial number of nodes in each element */ elem[e].num_nodes = n ; /* the element numbers must be contiguous */ // if (elem[e].id != e+1) { // fprintf(stderr, "ERROR - invalid element number: %d %d\n", // elem[e].id, e+1 ); // } if (elem[e].material == 0) { elem[e].material = 1; } else { /* get material from property sheet */ elem[e].material = prop[elem[e].material-1].mat; } } if (numlin && numquad) { fprintf(stderr, "ERROR - both linear and quadratic elements exist!\n"); exit(1); } /* Now check the node data */ // for( e = 0 ; e < numnp ; ++e ) { /* the node numbers must be contiguous */ // if (node[e].id != e+1) { // fprintf(stderr, "ERROR - invalid node number: %d %d\n", // elem[e].id, e+1 ); // } // } /* Now check the fixity data */ if (numlin) { /* no fixity for linear elements */ if (numfixity > 0) { fprintf(stderr, "Note: fixity not allowed for linear elements\n"); } numfixity = 0; } numapp = 0; for( e = 0 ; e < numfixity ; ++e ) { /* the fixity numbers must exist */ // if (fixity[e].node > numnp) { // fprintf(stderr, "ERROR - fixity number (%d) out of range\n", // fixity[e].node ); // fixity[e].node = 0; // } if (fixity[e].component > 2) { /* count number applied disps */ ++numapp; } } /* Now check the force data */ if (numlin) { /* no forces for linear elements */ if (numforce > 0) { fprintf(stderr, "Note: forces not allowed for linear elements\n"); } numforce = 0; } for( e = 0 ; e < numforce ; ++e ) { /* the force numbers must exist */ if (force[e].node > numnp) { fprintf(stderr, "ERROR - force number (%d) out of range\n", force[e].node ); force[e].node = 0; } /* check the load case */ if (force[e].set > MAX_CASE || force[e].set < 1) { fprintf(stderr, "ERROR - force case (%d) out of range\n", force[e].set ); force[e].node = 0; } else { load_types[force[e].set-1] = TYP_NODAL; } } /* Set up the load types for each load case. Applied displacements ** always go in load case one. Need to check for other loads in ** that case. */ if (numapp) { if (load_types[0] != TYP_NONE) { int i; /* try to find another free load case for the loads */ for( i = 0 ; i < MAX_CASE ; ++i ) { if (load_types[i] == TYP_NONE) { load_types[i] = load_types[0]; load_types[0] = TYP_APPDISP; load_swap[0] = i; load_swap[i] = 0; break; } } /* if none available, ignore the applied disps */ if (load_types[0] != TYP_APPDISP) { fprintf(stderr,"ERROR - load case 1 is not free for " "applied displacements\n Applied displacements " "ignored\n"); for( e = 0 ; e < numfixity ; ++e ) { if (fixity[e].component > FIX_Y) { fixity[e].node = 0; } } } } else { load_types[0] = TYP_APPDISP; } } } void WriteMesh( fp ) FILE *fp ; { int ii, jj; int maxint, *nodemap, *matmap; /* set the default material number if necessary */ if ( nummat == 0 ) { nummat = 1 ; mat[0] = aluminum ; } if (debug) { fprintf(stderr,"Problem Title \"%s\"\n", problem_title); fprintf(stderr,"Number of nodes: %d\n", numnp); fprintf(stderr,"Number of elements: %d\n", numel); fprintf(stderr,"Number of materials: %d\n", nummat); fprintf(stderr,"Number of forces: %d\n", numforce); fprintf(stderr,"Number of fixity: %d\n", numfixity); } fprintf(fp, "%.80s\n", problem_title) ; fprintf(fp, "%5d %5d %5d %5d\n", numnp, numel, nummat, probtype ) ; /* material number is implicitly ii+1 */ for( ii = 0 ; ii < nummat ; ii++ ) { fprintf(fp,"%5d",mat[ii].type); for( jj = 0 ; jj < NUM_MAT_PROPS ; jj++ ) { fprintf(fp, "%10.2E", mat[ii].props[jj] ) ; } fprintf(fp, "\n" ) ; } /* * Build the node map. This is the easy way to renumber the * nodes to be contiguous. */ maxint = 0; for( ii = 0 ; ii < numnp ; ++ii ) { maxint = max(node[ii].id,maxint); } nodemap = Malloc(maxint+1,int); for( ii = 0 ; ii < numnp ; ++ii ) { nodemap[node[ii].id] = ii+1; } /* * Build the material map. This is the easy way to renumber the * numbers to be contiguous. */ maxint = 0; for( ii = 0 ; ii < nummat ; ++ii ) { maxint = max(mat[ii].id,maxint); } matmap = Malloc(maxint+1,int); for( ii = 0 ; ii < nummat ; ++ii ) { matmap[mat[ii].id] = ii+1; } /* * write elements */ for( ii = 0 ; ii < numel ; ii++ ) { /* Hack - a test case for corner nodes only. */ if ( elem[ii].num_nodes == 3 ) { fprintf(fp, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d\n", ii+1, matmap[elem[ii].material], nodemap[elem[ii].node[0]], 0, nodemap[elem[ii].node[1]], 0, nodemap[elem[ii].node[2]], 0, 0, 0 ); } else if ( elem[ii].num_nodes == 4 ) { fprintf(fp, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d\n", ii+1, matmap[elem[ii].material], nodemap[elem[ii].node[0]], 0, nodemap[elem[ii].node[1]], 0, nodemap[elem[ii].node[2]], 0, nodemap[elem[ii].node[3]], 0 ); } else if ( elem[ii].num_nodes == 6 ) { fprintf(fp, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d\n", ii+1, matmap[elem[ii].material], nodemap[elem[ii].node[0]], nodemap[elem[ii].node[1]], nodemap[elem[ii].node[2]], nodemap[elem[ii].node[3]], nodemap[elem[ii].node[4]], nodemap[elem[ii].node[5]], nodemap[elem[ii].node[6]], nodemap[elem[ii].node[7]] ); } else if ( elem[ii].num_nodes == 8 ) { fprintf(fp, "%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d\n", ii+1, matmap[elem[ii].material], nodemap[elem[ii].node[0]], nodemap[elem[ii].node[1]], nodemap[elem[ii].node[2]], nodemap[elem[ii].node[3]], nodemap[elem[ii].node[4]], nodemap[elem[ii].node[5]], nodemap[elem[ii].node[6]], nodemap[elem[ii].node[7]] ); } else { fprintf(stderr,"ERROR - bad number of nodes for element %d: %d\n", ii+1, elem[ii].num_nodes ) ; } } /* * write nodes */ for( ii = 0 ; ii < numnp ; ii++ ) { fprintf(fp, "%5d%22.6E%22.6E\n", ii+1, node[ii].x, node[ii].y ) ; } /***************************************************************** ** Write the optional data */ if (numfixity > 0) { fprintf(fp, "AFIXITY\n %d\n", numfixity); for( ii = 0 ; ii < numfixity ; ii++ ) { fprintf(fp, " %d %d %g\n", nodemap[fixity[ii].node], fixity[ii].component, fixity[ii].value); } fprintf(fp, "LOADTYP\n"); for( ii = 0 ; ii < MAX_CASE ; ++ii ) { fprintf(fp, " %d", load_types[ii]); } fprintf(fp, "\n"); } if (numforce > 0) { if (numfixity == 0) { fprintf(fp, "LOADTYP\n"); for( ii = 0 ; ii < MAX_CASE ; ++ii ) { fprintf(fp, " %d", load_types[ii]); } fprintf(fp, "\n"); } fprintf(fp, "ALOADS\n %d\n", numforce); for( ii = 0 ; ii < numforce ; ii++ ) { fprintf(fp, " %d %d %g %g\n", nodemap[force[ii].node], load_swap[force[ii].set-1], force[ii].x, force[ii].y); } } Free(nodemap); Free(matmap); } /********************************************************************** ** Process the file and write the mesh. */ void ProcessFile( in_fname, out_fname ) char *in_fname ; char *out_fname ; { FILE *fp ; fp = OpenFile( in_fname, "r" ) ; ReadNASTRAN( fp ) ; fclose( fp ) ; CheckInputData() ; fp = OpenFile( out_fname, "w" ) ; WriteMesh( fp ) ; fclose( fp ) ; printf("\n%s: Done with conversion.\n", in_fname); } /********************************************************************** ** Main Program */ int main( argc, argv ) int argc ; char **argv ; { int iargc = argc; char **iargv = argv; /* process the command line options */ for(--iargc,++iargv; iargc > 0 ;--iargc,++iargv) { if (*iargv[0] == '-') { if (strcmp(iargv[0], "-onemat") == 0) { onemat = 1; } else if (strcmp(iargv[0], "-meshonly") == 0) { meshonly = 1; } else if (strcmp(iargv[0], "-debug") == 0) { debug = 1; } else if (strcmp(iargv[0], "-overwrite") == 0) { overwrite = 1; } else if (strcmp(iargv[0], "-?") == 0) { fprintf(stderr,"usage: %s\n", usage); fprintf(stderr,"%s\n", purpose); exit(1); } else { fprintf(stderr,"Bad argument: \"%s\"\n", iargv[0]); fprintf(stderr,"usage: %s\n", usage); fprintf(stderr,"%s\n", purpose); exit(1); } } else { break; } } argc = iargc; argv = iargv; /* check what's left on command line */ if ( argc == 0 ) { printf("%s\n", purpose) ; } if (argc > 0) { strcpy(in_fname,argv[0]) ; } if (argc > 1) { strcpy(out_fname,argv[1]) ; } /* get the files from the user, if necessary, and process them */ GetFiles( in_fname, out_fname ) ; ProcessFile( in_fname, out_fname ) ; printf("\n\n") ; return 0 ; }