/* ** Header: @(#) castofranc.c 1.8 10 May 1996 17:56:40 Last Update: 01 Aug 1995 */ /******************************************************************** This file translates one or more casca files to an input file suitable for Franc with capability of layers. AUTHOR : Dr. Daniel Swenson, originally for cracker Hacked by Sudhir Rehacked by Krish Complete rewrite: 8-17-94 Mark A. James ********************************************************************/ /* ** General comment by Dan Swenson about the purpose of this program. ** ** The ansys/franc translator does a search to ensure that faces are never ** added that completely encircle an empty space unless that is actually a ** hole. If that happens (that is, you add a circle of elements around a ** space), the topology gets confused and thinks that the space is a hole ** (face type 1, I believe). Then when you try to add the last element to ** fill the hole, things don't work right. We talked to Wash about this ** and there did not seem to be a way around the problem other than ensuring ** that this situation never occurrs. The translator's search makes sure ** that elements are added in a wave, never encircling a space unless a hole ** is really intended. Experience shows that this may regularly be ** necessary for ansys generated meshes, and periodically necessary for ** casca generated meshes. ** */ /* ** Note that this software assumes T6 and Q8 elements... ** No Q4 and T3! */ #include #include #include #define Calloc(n,t) ((t*)calloc( n, sizeof(t) )) #define Free(p) if(p) { free( p ) ; } #define Realloc( p, n, t ) ((t*)realloc( p, (n)*sizeof(t) )) #define REC_NUM 10 #define REC_LEN 5 #define LEN 512 #define NUMNODES 8 /* Number of nodes for each element */ #define NUMEDGES 4 /* Number of edges for each element */ #define NUM_MAT_PROPS 12 #ifndef True #define True 1 #define False 0 #endif #define Prob_Undefined -1 #define Prob_Axisymmetric 0 #define Prob_PlaneStress 1 #define Prob_PlaneStrain 2 #define Prob_Bending 3 typedef char Name[LEN] ; typedef struct { double x, y ; int number ; } Node ; typedef struct { int mat_id ; double mat_props[NUM_MAT_PROPS]; } Material ; typedef struct { int head ; int tail ; int right_elem ; int right_elem_edge ; int left_elem ; int left_elem_edge ; } Edge ; typedef struct { int num_nodes ; int node[NUMNODES] ; /* Nodes for each element */ int material ; int map_status ; int edges[NUMEDGES] ; } Element ; typedef struct { Name file_name ; Name title ; int num_nodes ; int num_elems ; int num_mats ; int num_edges ; int num_edges_alloced ; int num_mapped ; int prob_type ; int prev_elem ; int *mat_map ; int *elem_map ; Material *mats ; Node *nodes ; Element *elems ; Edge *edges ; } Layer ; typedef struct { Name file_name ; Name title ; int num_layers ; int num_mats ; int one_mat ; int renumber_elements ; int prob_type ; Layer *layers ; } Mesh ; void LayerAllocate( layer ) Layer *layer ; { layer->mat_map = Calloc( layer->num_mats, int ) ; layer->mats = Calloc( layer->num_mats, Material ) ; layer->elem_map = Calloc( layer->num_elems, int ) ; layer->elems = Calloc( layer->num_elems, Element ) ; layer->nodes = Calloc( layer->num_nodes, Node ) ; } void LayerFree( layer ) Layer *layer ; { } void extract( line, len, num, n ) char *line ; int len; /* length od each sub-record to extract */ int num; /* number of sub-records to extract */ int *n; { char dig[256] ; int i ; if (len > 255) { perror(" extract: length out of range") ; } for( i = 0 ; i < num ; ++i ) { strncpy( dig, line+i*len, len ) ; dig[len] = '\0' ; n[i] = atoi(dig) ; } } void ReadLayer( layer, fp ) Layer *layer ; FILE *fp ; { char line[LEN]; int rec[REC_NUM]; int i, j ; int idum ; fgets( layer->title, LEN, fp ) ; fgets(line, LEN, fp); sscanf(line, "%d %d %d %d", &layer->num_nodes, &layer->num_elems, &layer->num_mats, &layer->prob_type); LayerAllocate( layer ) ; for( i = 0 ; i < layer->num_mats ; ++i ) { fscanf( fp, "%d", &layer->mats[i].mat_id); for ( j = 0 ; j < NUM_MAT_PROPS; ++j ){ fscanf( fp, "%lf", &layer->mats[i].mat_props[j]); } } /* read the extra newline character after fscanf from above */ fgets(line, LEN, fp); for( i = 0 ; i < layer->num_elems ; ++i ) { /* parse the fortran style records */ fgets(line, LEN, fp); extract(line, REC_LEN, REC_NUM, rec); layer->elems[i].material = rec[1]; for( j = 0 ; j < NUMNODES ; ++j ){ layer->elems[i].node[j] = rec[j + 2]; } for( j = 0 ; j < NUMNODES ; ++j ) { if ( layer->elems[i].node[j] == 0 ) { layer->elems[i].num_nodes = j ; break ; } } if ( layer->elems[i].num_nodes == 0 ) { layer->elems[i].num_nodes = NUMNODES ; } } for( i = 0 ; i < layer->num_nodes ; ++i ) { fscanf( fp, "%d ", &idum ); fscanf( fp, "%lf %lf", &layer->nodes[i].x, &layer->nodes[i].y) ; } } void ReadData( mesh ) Mesh *mesh ; { int i ; FILE *fp ; for( i = 0 ; i < mesh->num_layers ; ++i ) { fp = fopen( mesh->layers[i].file_name, "r") ; if( fp == NULL ) { fprintf(stderr, "\n*** Problems opening data file \"%s\" ***\n\n", mesh->layers[i].file_name ) ; exit(0) ; } ReadLayer( &mesh->layers[i], fp ) ; fclose( fp ) ; } } void StripNewline( string ) char *string ; { char *str ; /* * strip the newline character, strtok() seems to behave differently * for a zero length string (only a newline in the string) */ for( str = string ; *str != '\0' ; ++str ) { if ( *str == '\n' ) { *str = '\0' ; } } } int SuffixChk( str, suf ) char *str ; char *suf ; { char *s ; s = strstr( str, suf ) ; if ( s ) { return ( strcmp(s,suf) == 0 ) ; } return 0 ; } void ValidateFileName( name, len ) char *name ; int len ; { /* * If the name is missing the suffix, and if there is room in the * string, add the suffix */ if ( SuffixChk( name, ".inp" ) == 0 ) { if ( (int)(strlen(name) + 4) < (int)len ) { strcat( name, ".inp" ) ; } } } void GetFileName( name, len, fp ) char *name ; int len ; FILE *fp ; { fgets(name,len,fp) ; StripNewline( name ) ; ValidateFileName( name, len ) ; } void GetFiles( mesh ) Mesh *mesh ; { int i ; fprintf(stderr,"\n") ; for( i = 0 ; i < mesh->num_layers ; ++i ) { fprintf(stderr,"Enter name of f2d/L .inp file: ") ; fflush(stderr) ; /* fgets(mesh->layers[i].file_name,LEN,stdin) ; */ GetFileName(mesh->layers[i].file_name,LEN,stdin) ; /* StripNewline( mesh->layers[i].file_name ) ; */ } fprintf(stderr,"\nEnter name for layered .inp file: ") ; fflush(stderr) ; /* fgets(mesh->file_name,LEN,stdin) ; */ GetFileName(mesh->file_name,LEN,stdin) ; /* StripNewline( mesh->file_name ) ; */ fprintf(stderr, "\nEnter problem title: ") ; fflush(stderr) ; fgets( mesh->title,LEN,stdin) ; StripNewline( mesh->title ) ; } void ProcessMaterials( mesh ) Mesh *mesh ; { int i, j ; for( i = 0 ; i < mesh->num_layers ; ++i ) { for( j = 0 ; j < mesh->layers[i].num_mats ; ++j ) { if ( mesh->one_mat ) { mesh->layers[i].mat_map[j] = 1 ; } else { mesh->layers[i].mat_map[j] = mesh->num_mats + j + 1 ; } } mesh->num_mats += mesh->layers[i].num_mats ; } if ( mesh->one_mat ) { mesh->num_mats = 1 ; } } #define alloc_quantum 100 static Edge null_edge ; Edge *NewEdge( layer ) Layer *layer ; { if ( layer->edges == 0 ) { layer->num_edges_alloced = alloc_quantum ; layer->edges = Calloc( layer->num_edges_alloced, Edge ) ; } else if ( layer->num_edges == layer->num_edges_alloced ) { int num = layer->num_edges_alloced ; layer->num_edges_alloced += alloc_quantum ; layer->edges = Realloc( layer->edges, layer->num_edges_alloced, Edge ) ; while( num < layer->num_edges_alloced ) { layer->edges[num++] = null_edge ; } } return &layer->edges[layer->num_edges++] ; } void AddEdge( layer, head, tail, el, ed ) Layer *layer ; int head ; int tail ; int el ; int ed ; { int i ; int found = 0 ; Edge *edges = layer->edges ; for( i = 0 ; i < layer->num_edges ; ++i ) { if ( edges[i].head == head || edges[i].tail == head ) { if ( edges[i].head == tail || edges[i].tail == tail ) { found = 1 ; break ; } } } if ( found ) { edges[i].left_elem = el + 1 ; edges[i].left_elem_edge = ed + 1 ; layer->elems[el].edges[ed] = i+1 ; } else { Edge *edge ; edge = NewEdge( layer ) ; edge->head = head ; edge->tail = tail ; edge->right_elem = el + 1 ; edge->right_elem_edge = ed + 1 ; layer->elems[el].edges[ed] = layer->num_edges ; } } void ProcessEdges( layer ) Layer *layer ; { int i ; for( i = 0 ; i < layer->num_elems ; ++i ) { int j ; int *node = layer->elems[i].node ; int nn = layer->elems[i].num_nodes ; for( j = 0 ; j < nn/2 ; ++j ) { int head = node[(j*2+2)%nn] ; int tail = node[j*2] ; AddEdge( layer, head, tail, i, j ) ; } } } #define Fail -1 #define MapWaiting 0 #define MapFinished 1 int CountAdjElem( layer, test ) Layer *layer ; int test ; { int j ; int num = 0 ; Element *elems = layer->elems ; int *adj = elems[test].edges ; Edge *edges = layer->edges ; /* ** The adjacency list uses 1 based indexing (rather than 0 based) ** because 0 is the default initialized "empty or error" state. ** Note that this assumes T6 and Q8 elements. */ /* * Count the number of elements adjacent to this one that have already * been renumbered. Note that none of the elements adjacent to this one * should be "done" because an element is not done until all of the * adjacent elements are added. */ for( j = 0 ; j < elems[test].num_nodes/2 ; ++j ) { int rs ; int ls ; int e ; e = adj[j] - 1 ; if ( edges[e].right_elem > 0 ) { rs = elems[edges[e].right_elem-1].map_status ; if ( rs == MapFinished ) { num += 1 ; } } if ( edges[e].left_elem > 0 ) { ls = elems[edges[e].left_elem-1].map_status ; if ( ls == MapFinished ) { num += 1 ; } } } return num ; } int GetAdjElem( layer, test ) Layer *layer ; int test ; { int j ; int num ; int max_num = -1 ; int max_elem = Fail ; Element *elems = layer->elems ; int *adj = elems[test].edges ; Edge *edges = layer->edges ; /* ** The adjacency list uses 1 based indexing (rather than 0 based) ** because 0 is the default initialized "empty or error" state. ** Note that this assumes T6 and Q8 elements. */ /* * Loop on the edges for this element and find the element with * the most common edges. This helps us add elements in a wave front. */ for( j = 0 ; j < elems[test].num_nodes/2 ; ++j ) { int rs ; int ls ; int e ; e = adj[j] - 1 ; if ( edges[e].right_elem > 0 ) { rs = elems[edges[e].right_elem-1].map_status ; if ( rs == MapWaiting ) { num = CountAdjElem( layer, edges[e].right_elem-1 ) ; if ( num > max_num ) { max_num = num ; max_elem = edges[e].right_elem-1 ; } } } if ( edges[e].left_elem > 0 ) { ls = elems[edges[e].left_elem-1].map_status ; if ( ls == MapWaiting ) { num = CountAdjElem( layer, edges[e].left_elem-1 ) ; if ( num > max_num ) { max_num = num ; max_elem = edges[e].left_elem-1 ; } } } } return max_elem ; } int GetFirstElem( layer ) Layer *layer ; { int i, j ; Element *elems = layer->elems ; Edge *edges = layer->edges ; for( i = 0 ; i < layer->num_elems ; ++i ) { int *adj = elems[i].edges ; /* ** The adjacency list uses 1 based indexing (rather than 0 based) ** because 0 is the default initialized "empty or error" state. ** Note that this assumes T6 and Q8 elements. */ for( j = 0 ; j < elems[i].num_nodes/2 ; ++j ) { int e ; /* any element on the boundary will do */ e = adj[j] - 1 ; if ( edges[e].right_elem == 0 || edges[e].left_elem == 0 ) { return i ; } } } return 0 ; } int GetBruteForceElem( layer ) Layer *layer ; { int i ; for( i = 0 ; i < layer->num_elems ; ++i ) { if ( layer->elems[i].map_status == MapFinished ) { int forced = GetAdjElem( layer, i ) ; if ( forced != Fail ) { return forced ; } } } fprintf(stderr,"ERROR - no more elements to Process!\n") ; exit(1) ; } int GetElem( layer ) Layer *layer ; { int elem ; /* * Get an element on the boundary if this is the first time */ if ( layer->num_mapped == 0 ) { return GetFirstElem( layer ) ; } /* * Look for an element adjacent to the current element * (on the wave front). If there are none, search globally * for an element on the wavefront. */ elem = GetAdjElem( layer, layer->prev_elem ) ; if ( elem == Fail ) { return GetBruteForceElem( layer ) ; } return elem ; } void UpdateMapStatus( layer, elem ) Layer *layer ; int elem ; { Element *elems = layer->elems ; int *adj = elems[elem].edges ; Edge *edges = layer->edges ; layer->prev_elem = elem ; elems[elem].map_status = MapFinished ; } void RenumberNodes( layer ) Layer *layer ; { int i, j ; int num_nodes = 0 ; Element *elems = layer->elems ; Node *nodes = layer->nodes ; /* * Mark the nodes with their new node numbers and update the number * in the element connectivity list. */ for( j = 0 ; j < layer->num_elems ; ++j ) { int *node = elems[j].node ; for( i = 0 ; i < elems[j].num_nodes ; ++i ) { if ( nodes[node[i]-1].number == 0 ) { ++num_nodes ; nodes[node[i]-1].number = num_nodes ; } node[i] = nodes[node[i]-1].number ; } } /* * Now compress out all of the unused nodes. */ for( i = j = 0 ; j < layer->num_nodes ; ++j ) { if ( nodes[j].number > 0 ) { if ( j > i ) { nodes[i] = nodes[j] ; } ++i ; } } if ( i < num_nodes ) { fprintf(stderr,"ERROR - problem during node compression!\n") ; abort() ; } layer->num_nodes = num_nodes ; } void RenumberElements( layer ) Layer *layer ; { int e ; while( layer->num_mapped < layer->num_elems ) { e = layer->elem_map[layer->num_mapped++] = GetElem( layer ) ; UpdateMapStatus( layer, e ) ; } } void ProcessNodes( mesh ) Mesh *mesh ; { int i ; for( i = 0 ; i < mesh->num_layers ; ++i ) { Layer *layer = &mesh->layers[i] ; RenumberNodes( layer ) ; } } void ProcessElements( mesh ) Mesh *mesh ; { int i, j ; if ( mesh->renumber_elements ) { for( i = 0 ; i < mesh->num_layers ; ++i ) { Layer *layer = &mesh->layers[i] ; ProcessEdges( layer ) ; RenumberElements( layer ) ; } } else { for( i = 0 ; i < mesh->num_layers ; ++i ) { Layer *layer = &mesh->layers[i] ; for( j = 0 ; j < mesh->layers[i].num_elems ; ++j ) { layer->elem_map[j] = j ; } } } } void ProcessProbType( mesh ) Mesh *mesh ; { if ( mesh->prob_type == Prob_Undefined ) { mesh->prob_type = mesh->layers[0].prob_type ; } } int MapElem( layer, elem ) Layer *layer ; int elem ; { return layer->elem_map[elem] ; } int MapMat( layer, elem ) Layer *layer ; int elem ; { return layer->mat_map[layer->elems[elem].material-1] ; } void ProcessData( mesh ) Mesh *mesh ; { int i, j, k ; FILE *fp ; ProcessProbType( mesh ) ; ProcessMaterials( mesh ) ; ProcessElements( mesh ) ; ProcessNodes( mesh ) ; if ( strlen(mesh->file_name) == 0 ) { fp = stdout ; } else { fp = fopen(mesh->file_name, "w") ; if( fp == NULL ) { fprintf(stderr,"\n*** Problems opening output file \"%s\" ***\n\n", mesh->file_name ) ; exit(0) ; } } fprintf( fp, "%.40s\n", mesh->title) ; fprintf( fp, "%5d %5d %5d\n", mesh->num_layers, mesh->num_mats, mesh->prob_type ) ; if ( mesh->one_mat ) { Material *mat = &mesh->layers[0].mats[0] ; fprintf( fp, "%5d", mat->mat_id ) ; for( k = 0 ; k < NUM_MAT_PROPS ; ++k ) { fprintf( fp,"%10.2E", mat->mat_props[k]) ; } fprintf( fp,"\n" ) ; } else { for( i = 0 ; i < mesh->num_layers ; ++i ) { for( j = 0 ; j < mesh->layers[i].num_mats ; ++j ) { Material *mat = &mesh->layers[i].mats[j] ; fprintf( fp, "%5d", mat->mat_id ) ; for( k = 0 ; k < NUM_MAT_PROPS ; ++k ) { fprintf( fp,"%10.2E", mat->mat_props[k]) ; } fprintf( fp,"\n" ) ; } } } for( i = 0 ; i < mesh->num_layers ; ++i ) { int mat ; int elem ; fprintf( fp,"%5d %5d\n", mesh->layers[i].num_nodes, mesh->layers[i].num_elems ) ; for( j = 0 ; j < mesh->layers[i].num_elems ; ++j ) { elem = MapElem( &mesh->layers[i], j ) ; mat = MapMat( &mesh->layers[i], elem ) ; fprintf( fp, "%5d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", j+1, mat, mesh->layers[i].elems[elem].node[0], mesh->layers[i].elems[elem].node[1], mesh->layers[i].elems[elem].node[2], mesh->layers[i].elems[elem].node[3], mesh->layers[i].elems[elem].node[4], mesh->layers[i].elems[elem].node[5], mesh->layers[i].elems[elem].node[6], mesh->layers[i].elems[elem].node[7] ); } /* * The nodes have been renumbered and compressed, but not * reordered. Here we reorder them by brute force. */ for( k = 0 ; k < mesh->layers[i].num_nodes ; ++k ) { for( j = 0 ; j < mesh->layers[i].num_nodes ; ++j ) { if ( mesh->layers[i].nodes[j].number == k+1 ) { fprintf( fp, "%5d %22.6E %22.6E\n", k+1, mesh->layers[i].nodes[j].x, mesh->layers[i].nodes[j].y ) ; break ; } } } } fclose( fp ) ; } int PromptYesNo( prompt ) char *prompt ; { int rtn ; char line[LEN] ; for(;;) { fprintf(stderr,"%s (y,n): ", prompt ) ; fflush(stderr) ; fgets(line, LEN, stdin) ; if ( line[0] == 'y' || line[0] == 'Y' ) { rtn = True ; break ; } else if ( line[0] == 'n' || line[0] == 'N' ) { rtn = False ; break ; } } return rtn ; } #define OPTIONS "[-search | -nosearch] [-onemat] [-o out_file] \n\ [-bending | -axisymmetric | -planestress | -planestrain] franc_files..." void arg_error(argc, argv, bad) int argc ; char **argv ; int bad ; { fprintf(stderr,"Bad argument: %s\n", argv[bad] ) ; fprintf(stderr,"Usage: %s %s\n", argv[0], OPTIONS ) ; exit(1) ; } static int perform_search = True ; /* default is to perform search */ static int one_mat = False ; /* compress out materials */ static int prob_type = Prob_Undefined ; Mesh *MeshAlloc( num ) int num ; { Mesh *mesh ; mesh = Calloc( 1, Mesh ) ; mesh->num_layers = num ; mesh->layers = Calloc( num, Layer ) ; mesh->one_mat = one_mat ; mesh->renumber_elements = perform_search ; mesh->prob_type = prob_type ; return mesh ; } Mesh *ProcessArgs( argc, argv ) int argc ; char **argv ; { int i, j ; Name file_name ; Mesh *mesh = 0 ; file_name[0] = '\0' ; for( i = 1 ; i < argc ; ++i ) { if ( *argv[i] == '-' ) { if ( strcmp( argv[i], "-search" ) == 0 ) { perform_search = 1 ; } else if ( strcmp( argv[i], "-nosearch" ) == 0 ) { perform_search = 0 ; } else if ( strcmp( argv[i], "-onemat" ) == 0 ) { one_mat = True ; } else if ( strcmp( argv[i], "-bending" ) == 0 ) { prob_type = Prob_Bending ; } else if ( strcmp( argv[i], "-axisymmetric" ) == 0 ) { prob_type = Prob_Axisymmetric ; } else if ( strcmp( argv[i], "-planestress" ) == 0 ) { prob_type = Prob_PlaneStress ; } else if ( strcmp( argv[i], "-planestrain" ) == 0 ) { prob_type = Prob_PlaneStrain ; } else if ( strcmp( argv[i], "-o" ) == 0 ) { if ( ++i < argc ) { strcpy( file_name, argv[i] ) ; ValidateFileName( file_name, LEN ) ; } } else { arg_error(argc,argv,1) ; } } else { break ; } } /* * Look for files on the command line */ if ( i < argc ) { mesh = MeshAlloc( argc-i ) ; for( j = 0 ; i < argc ; ++i, ++j ) { strcpy( mesh->layers[j].file_name, argv[i] ) ; ValidateFileName( mesh->layers[j].file_name, LEN ) ; } if ( strlen(file_name) > 0 ) { strcpy( mesh->file_name, file_name ) ; ValidateFileName( mesh->file_name, LEN ) ; } } return mesh ; } #define CHK_MESH_PROMPT "Check mesh for holes" #define CMPRSS_MAT_PROMPT "Map all materials" #define PURPOSE "\nThis program translates franc files into layered franc format\n" int main(argc, argv) int argc ; char **argv ; { char line[LEN] ; Mesh *mesh ; int num ; mesh = ProcessArgs( argc, argv ) ; if ( mesh == 0 ) { fprintf(stderr, PURPOSE ) ; fprintf(stderr,"For file names; .inp is assumed \n"); /* perform_search = PromptYesNo( CHK_MESH_PROMPT ) ; */ /* one_mat = PromptYesNo( CMPRSS_MAT_PROMPT ) ; one_mat = !one_mat ; */ fprintf(stderr,"\nEnter number of layers : "); fflush( stdout ) ; fgets( line, LEN, stdin ) ; sscanf( line,"%d",&num ); mesh = MeshAlloc( num ) ; GetFiles( mesh ) ; } ReadData( mesh ) ; ProcessData( mesh ) ; return 0 ; }