/***********************************************************************
*
* ELMER, A Computational Fluid Dynamics Program.
*
* Copyright 1st April 1995 - , Center for Scientific Computing,
* Finland.
*
* All rights reserved. No part of this program may be used,
* reproduced or transmitted in any form or by any means
* without the written permission of CSC.
*
* Address: Center for Scientific Computing
* Tietotie 6, P.O. BOX 405
* 02101 Espoo, Finland
* Tel. +358 0 457 2001
* Telefax: +358 0 457 2302
* EMail: Jari.Jarvinen@csc.fi
************************************************************************/
/***********************************************************************
Program: ELMER Front
Module: ecif_inputFidap.cpp
Language: C++
Date: 27.04.99
Version: 1.00
Author(s): Martti Verho
Revisions:
Abstract: Implementation
************************************************************************/
#include "ecif_body.h"
#include "ecif_body2D.h"
#include "ecif_body3D.h"
#include "ecif_bodyElement.h"
#include "ecif_bodyElement2D.h"
#include "ecif_bodyElement3D.h"
#include "ecif_control.h"
#include "ecif_geometry.h"
#include "ecif_inputFidap.h"
#include "ecif_mesh.h"
#include "ecif_model.h"
#include "ecif_timer.h"
#include "ecif_userinterface.h"
extern char read_buffer[];
// Indices to the special reorder table for element types
const int fidapReorderTableIndex_203 = 0;
const int fidapReorderTableIndex_510 = 1;
const int fidapReorderTableIndex_718 = 2;
const int fidapReorderTableIndex_808 = 3;
const int fidapReorderTableIndex_809 = 4;
const int fidapReorderTableIndex_827 = 5;
// We have to reorder Fidap nodes to match Elmer numbering
const int fidapReorderTable[][MAX_NOF_NODES] = {
{0,2,1}, // Line 203
{0,2,5,9,1,4,3,6,7,8}, // Tetra 510
// NOTE: 718 is delivered to Elmer as 706, but here is the complete reorder! (ok?)
{0,2,5,12,14,17,1,4,3,6,7,8,10,11,9,13,16,15}, // Wedge 718
{0,1,3,2,4,5,7,6}, // Brick 808
{0,1,3,2,4,5,7,6, 8}, // Brick 809 (1 in center)
// NOTE: 827 is delivered to Elmer as 820, but here is the complete reorder!
{0,2,8,6,18,20,26,24,1,5,7,3,9,11,17,15,19,23,25,21,10,14,16,12,4,22,13} // Brick 827
};
InputFidap::InputFidap(enum ecif_modelDimension m_dim,
ifstream& in_file, char* in_filename):
Input(m_dim, in_file, in_filename)
{
for (short i = 0; i < 1 + MAX_NOF_ELEM_CODES; i++)
elementCodeCounters[i] = 0;
nofElementGroups = 0;
dataDimension = ECIF_ND;
}
InputFidap::~InputFidap()
{
}
Body*
InputFidap::findExistingBody(FidapElementGroupInfo* gi)
{
int index = 0;
while (true) {
Body* body = model->getBody(index++);
if (body==NULL) break;
if ( LibFront::ncEqual((char*)body->getName(), gi->entityName) ) {
return body;
}
}
return NULL;
}
BodyElement*
InputFidap::findExistingBoundary(FidapElementGroupInfo* gi)
{
int index = 0;
while (true) {
BodyElement* be = model->getBoundary(index++);
if (be==NULL) break;
if ( LibFront::ncEqual((char*)be->getName(), gi->entityName) ) {
return be;
}
}
return NULL;
}
Rc
InputFidap::findMaxExternalIds(int& max_ext_nd_id, int& max_ext_el_id)
{
enum fidapKeywordId keyword = FIDAP_NO_ID;
bool count_only = true;
while ( !infile.eof() ) {
// Read new line
readFileLine(infile, read_buffer);
// Check if it was an interesting keyword line
keyword = next_is_keyword_line(read_buffer);
if ( keyword == FIDAP_NO_ID)
continue;
// Read element group
// ==================
if ( keyword == FIDAP_ELEMENT_GROUPS_ID ) {
int element_group_counter = 0;
while ( element_group_counter < nofElementGroups &&
!infile.eof()
) {
element_group_counter++;
// Read one group
FidapElementGroupInfo gi;
// Check that group is ok
if ( !readElementGroupInfo(gi) )
return ECIF_ERROR;
if ( !setElementType(gi) )
return ECIF_ERROR;
// Read group elements
// ===================
int element_counter = 0;
readElements(gi, element_counter, max_ext_el_id, count_only);
}
}
// Read nodes
// ==========
else if ( keyword == FIDAP_NODAL_COORDINATES_ID ) {
int node_counter = 0;
readNodes(nofNodes, node_counter, max_ext_nd_id, count_only);
}
} // while !eof
return ECIF_OK;
}
// NOTE: Fidap mesh dimension is read from the header and
// stored in the class attribute 'dimension'
//
enum ecif_modelDimension
InputFidap::findMeshModelDimension()
{
ecif_modelDimension box_dim = ECIF_ND;
ecif_modelDimension dim = ECIF_ND;
#if 0
RangeVector rv;
bool x_is_const = false;
bool y_is_const = false;
bool z_is_const = false;
meshBoundingBox.getRangeVector(rv);
// Find model dimension by boundary box
if ( isEqual(rv[0], rv[1]) ) {
x_is_const = true;
}
if ( isEqual(rv[2], rv[3]) ) {
y_is_const = true;
}
if ( isEqual(rv[4], rv[5]) ) {
z_is_const = true;
}
if ( !(x_is_const || y_is_const || z_is_const) ) {
box_dim = ECIF_3D;
} else if ( !( x_is_const || y_is_const) && z_is_const ) {
box_dim = ECIF_2D;
} else if ( !(x_is_const && y_is_const && z_is_const) ) {
box_dim = ECIF_1D;
} else {
box_dim = ECIF_ND;
}
#endif
box_dim = modelDimension;
// Find actual dimension
dim = findModelDimension(box_dim);
return dim;
}
enum fidapKeywordId
InputFidap::next_is_keyword_line(char* line_buffer)
{
if ( 0 == strncmp("NODAL COORDINATES", line_buffer, 17) )
return FIDAP_NODAL_COORDINATES_ID;
else if ( 0 == strncmp("ELEMENT GROUPS", line_buffer, 14) )
return FIDAP_ELEMENT_GROUPS_ID;
else if ( 0 == strncmp("VERSION", line_buffer, 7) )
return FIDAP_VERSION_ID;
else
return FIDAP_NO_ID;
}
Rc
InputFidap::readElementGroup(int& body_counter, int& bndr_counter,
int& element_counter, int& max_ext_elem_id,
bool count_only)
{
int element_group_counter = 0;
while ( element_group_counter < nofElementGroups &&
!infile.eof()
) {
element_group_counter++;
// Read one group
FidapElementGroupInfo gi;
// Check that group is ok
if ( !readElementGroupInfo(gi) )
return ECIF_ERROR;
if ( !setElementType(gi) )
return ECIF_ERROR;
gi.parentTag = NO_INDEX;
// Check elment type bulk/boundary
model->checkMeshElementType(gi.elementType,
gi.isBulk,
gi.isBoundary,
gi.isEdge);
// Bulk elements --> add elements to a body
// =============
if (gi.isBulk) {
nofBulkElements += gi.nofElements;
// Try to find an existing body
// ----------------------------
Body* body = findExistingBody(&gi);
// Create a new body
// -----------------
if (body == NULL) {
int int_id = ++body_counter; // Body internal id!
int ext_id = gi.id; // Body external id!
if ( modelDimension == ECIF_2D ) {
body = new Body2D(MESH_BODY, int_id, ext_id, 0, NULL);
} else if ( modelDimension == ECIF_3D ) {
body = new Body3D(MESH_BODY, int_id, ext_id, 0, NULL);
}
if (body != NULL) {
model->addBody(body);
body->setName(gi.entityName);
}
}
// Ok, home found/created for the bulk elements!
if ( body != NULL ) {
gi.parentTag = body->Tag();
}
// Boundary elements --> add elements to a boundary
// =================
} else if (gi.isBoundary) {
nofBoundaryElements += gi.nofElements;
// Try to find an existing boundary
// --------------------------------
BodyElement* be = findExistingBoundary(&gi);
// Create a new boundary
// ---------------------
if ( be == NULL ) {
int int_id = ++bndr_counter; // Internal id!
// Create a proper boundary (body element)
if ( modelDimension == ECIF_2D ) {
be = new BodyElement2D(int_id, NO_INDEX, NO_INDEX, gi.nofElements);
} else if ( modelDimension == ECIF_3D ) {
be = new BodyElement3D(int_id, NO_INDEX, NO_INDEX, gi.nofElements);
}
if (be != NULL) {
model->addBodyElement(be);
be->setName(gi.entityName);
}
}
// Ok, home found/created for the boundary elements!
if ( be != NULL ) {
gi.parentTag = be->Tag();
}
}
// Read group elements
// ===================
if ( ECIF_OK != readElements(gi, element_counter, max_ext_elem_id, count_only) ) {
return ECIF_ERROR;
}
}
return ECIF_OK;
}
// Read element group info
// Returns true if read was succesful
//
bool
InputFidap::readElementGroupInfo(FidapElementGroupInfo& gi)
{
static char key_buffer[80];
static char value_buffer[80];
eat_white(infile);
// First group info line
readFileLine(infile, read_buffer);
strstream strm1;
strm1 << read_buffer;
while( !strm1.eof() ) {
ws(strm1);
strm1.getline(key_buffer, 80, ':');
if ( 0 == strncmp(key_buffer, "GROUP", 5) )
strm1 >> gi.id;
if ( 0 == strncmp(key_buffer, "ELEMENTS", 8) )
strm1 >> gi.nofElements;
if ( 0 == strncmp(key_buffer, "NODES", 5) )
strm1 >> gi.nofNodes;
if ( 0 == strncmp(key_buffer, "GEOMETRY", 8) )
strm1 >> gi.fidap_geometry;
if ( 0 == strncmp(key_buffer, "TYPE", 4) )
strm1 >> gi.fidap_type;
}
// Second group info line
readFileLine(infile, read_buffer);
strstream strm2;
strm2 << read_buffer;
while( !strm2.eof() ) {
ws(strm2);
strm2.getline(key_buffer, 80, ':');
if ( 0 == strncmp(key_buffer, "ENTITY NAME", 11) )
strm2.getline(gi.entityName, 80 , '\n');
}
LibFront::trim(gi.entityName);
return true;
}
Rc
InputFidap::readElements(FidapElementGroupInfo& gi,
int& element_counter, int& max_ext_id,
bool count_only)
{
Rc rc;
int ext_el_id, ext_nd_id;
static int ext_node_ids[MAX_NOF_NODES];
static int ext_node_ids2[MAX_NOF_NODES]; // For reordering!
meshElementCode elem_code = model->convertElementType(gi.elementType);
if ( elem_code == MEC_000 ) {
return ECIF_ERROR;
}
short nof_nodes = MeshElementDesc[elem_code][DESC_NOF_NODES];
short i, j;
eat_white(infile);
int group_elem_counter = 0;
while ( group_elem_counter < gi.nofElements && !infile.eof() ) {
if ( !count_only ) {
theControlCenter->update(element_counter, GUI_UPDATE_INTERVAL);
}
int node_count = 0;
while ( node_count < nof_nodes ) {
// Element id
if ( node_count == 0 ) {
infile >> ext_el_id;
}
infile >> ext_nd_id;
ext_node_ids[node_count] = ext_node_ids2[node_count] = ext_nd_id;
node_count++;
}
if ( max_ext_id < ext_el_id ) {
max_ext_id = ext_el_id;
}
group_elem_counter++;
element_counter++;
if ( count_only ) continue;
// Apply possible preset reordering vector
if ( gi.fidap_reorder != NULL ) {
for (i = 0; i < nof_nodes; i++) {
ext_node_ids[i] = ext_node_ids2[ gi.fidap_reorder[i] ];
}
// Or apply possible generic reorder for non-ok element types
} else {
switch (gi.elementType) {
// These are ok
case 303: case 304:
case 404: case 405:
case 504: case 505:
case 706: case 707:
break;
// Others have a generic reordering
default:
for (i = 0, j = 0; j < nof_nodes - 1; i++, j += 2) {
ext_node_ids[i] = ext_node_ids2[j];
}
for (j = 1; j < nof_nodes; i++, j += 2) {
ext_node_ids[i] = ext_node_ids2[j];
}
break;
}
}
elementCodeCounters[elem_code]++;
// Add element to the model
rc = model->addMeshInputElement(gi.elementType, ext_el_id, gi.parentTag, gi.id, ext_node_ids);
if (gi.isBulk) {
nofInputBulkElements++;
} else if (gi.isBoundary) {
nofInputBoundaryElements++;
} else if (gi.isEdge) {
nofInputEdgeElements++;
} else {
nofInputVertexElements++;
}
if (rc != ECIF_OK) {
return rc;
}
} // while not eof()
return ECIF_OK;
}
bool
InputFidap::readNumericKeywordValue(char* line_buffer, char* keyword, int& value)
{
const int buffer_len = 80;
static char buffer[buffer_len];
if ( !readKeywordValue(line_buffer, keyword, buffer, buffer_len) )
return false;
value = atol(buffer);
return true;
}
bool
InputFidap::readStringKeywordValue(char* line_buffer, char* keyword, char* value_buffer)
{
const int buffer_len = 80;
static char buffer[buffer_len];
if ( !readKeywordValue(line_buffer, keyword, buffer, buffer_len) )
return false;
strcpy(buffer, value_buffer);
return true;
}
bool
InputFidap::readKeyword(char* line_buffer, char* buffer, int buffer_len)
{
strstream strm;
strm << line_buffer << ends;
if ( strm.eof() )
return false;
strm.getline(buffer, buffer_len, ':');
// Trim trailing blanks
int len = strlen(buffer);
int pos = len - 1;
while ( pos >= 0 && buffer[pos] == ' ' )
pos--;
buffer[1 + pos] = '\0';
return true;
}
bool
InputFidap::readKeywordValue(char* line_buffer, char* keyword, char* buffer, int buffer_len)
{
int strm_buf_len = strlen(line_buffer);
char* strm_buf = new char[1 + strm_buf_len];
strstream strm(strm_buf, 1 + strm_buf_len, ios::app);
strm << line_buffer << ends;
// Work buffer
char* work_buf = new char[1 + strm_buf_len];
char* tmp = work_buf;
bool found = false;
// Try to read keyword value
while ( !strm.eof() ) {
// Read next keyword
strm.getline(tmp, strm_buf_len, ':');
// Skip leading blanks
LibFront::trimLeft(tmp);
// If this was searched keyword
if ( LibFront::ncEqualPartial(tmp, keyword) ) {
found = true;
// Jump over the searched keyword
tmp += strlen(keyword);
// Make a new stream from what is left
reset(strm);
strm << tmp << ends;
break;
}
}
if (!found)
return false;
// Pick until next keyword to get the keyword value
// for the previous keyword!
strm.getline(tmp, strm_buf_len, ':');
// Skip backword the next keyword (until first blank)
int len = strlen(tmp);
while (len > 0 && tmp[len - 1] != ' ' )
len--;
tmp[len] = '\0';
// Trim blanks
LibFront::trim(tmp);
// Check that value fits to the final buffer
if ( strlen(tmp) <= buffer_len ) {
strcpy(buffer, tmp);
found = true;
}
else {
found = false;
}
delete[] strm_buf;
delete[] work_buf;
return found;
}
// NOTE: Model dimension is stored in this stage in the class
// attribute 'dimension' which is read from the mesh file header
//
Rc
InputFidap::readMeshData(int& element_counter, int& node_counter)
{
enum fidapKeywordId keyword = FIDAP_NO_ID;
bool count_only = false;
UserInterface* gui = theControlCenter->getGui();
int body_counter = 0;
int bndr_counter = 0;
int max_ext_el_id = -1;
int max_ext_nd_id = -1;
while ( !infile.eof() ) {
// Read new line
readFileLine(infile, read_buffer);
// Check if it was an interesting keyword line
keyword = next_is_keyword_line(read_buffer);
if ( keyword == FIDAP_NO_ID)
continue;
// Read elements (group)
// =====================
if ( keyword == FIDAP_ELEMENT_GROUPS_ID ) {
if ( ECIF_OK != readElementGroup(body_counter, bndr_counter, element_counter, max_ext_el_id, count_only) ) {
return ECIF_ERROR;
}
}
// Read nodes
// ==========
else if ( keyword == FIDAP_NODAL_COORDINATES_ID ) {
if ( ECIF_OK != readNodes(nofNodes, node_counter, max_ext_nd_id, count_only) ) {
return ECIF_ERROR;
}
model->setMeshNodes();
}
} // while !eof
return ECIF_OK;
}
// Create mesh geometry from Fidap neutral input file
//
// --Data should be in the following order in the input file:
// Nodes, Elements, Element groups
//
// --Those bulk and boundary elements which are not listed in groups, are processed later
// and the bodies/boundaries based on them are then created
//
// --Model dimension is known when nodes are read
//
bool
InputFidap::readMeshGeometry()
{
int dimension;
//---Header: Read dimension, nof nodes and elements
//
if (!readMeshHeader(dimension)) {
modelDimension = ECIF_ND;
infile.close();
return false;
}
if ( nofElements == 0 || nofNodes == 0 ) {
modelDimension = ECIF_ND;
return false;
}
if ( dimension == 1 ) {
dataDimension = ECIF_1D;
} else if ( dimension == 2 ) {
dataDimension = ECIF_2D;
} else if (dimension == 3 ) {
dataDimension = ECIF_3D;
} else {
dataDimension = ECIF_ND;
return false;
}
// Check input dimension, it cannot be smaller than
// data dimension!
// 1D not actually supported!
if ( inputDimension == ECIF_1D && dataDimension == ECIF_2D ) {
inputDimension = ECIF_2D;
}
if ( inputDimension == ECIF_2D && dataDimension == ECIF_3D ) {
inputDimension = ECIF_3D;
}
modelDimension = inputDimension;
model->setModelDimension(modelDimension);
findMaxExternalIds(maxExternalNodeId, maxExternalElementId);
//---Allocate mesh tables
// NOTE: This is total of bulk+bndr elements given explicitely in the file
model->allocateMeshInputElements(nofElements, maxExternalElementId);
model->allocateMeshNodes(nofNodes, maxExternalNodeId);
//---Read nodes and element groups
Rc rc;
infile.clear();
infile.seekg(0);
int element_counter = 0;
int node_counter = 0;
rc = readMeshData(element_counter, node_counter);
if (rc != ECIF_OK) {
modelDimension = ECIF_ND;
return false;
}
model->setModelDimension(modelDimension);
if (modelDimension == ECIF_ND) {
return false;
}
return true;
}
// All Fidap neutral files have similar header section
//
// NOTE: In header Nof-elements is sum of listed bulk and bndr elements!
//
bool
InputFidap::readMeshHeader(int& dimension)
{
readFileLine(infile, read_buffer);
if ( 0 != strncmp("** FIDAP NEUTRAL FILE", read_buffer, 21) ) {
return false;
}
readFileLine(infile, read_buffer, 5);
strstream strm;
strm << read_buffer;
if ( !(strm >> nofNodes >> nofElements >> nofElementGroups >> dimension) ) {
return false;
}
return true;
}
Rc
InputFidap::readNodes(int nof_nodes,
int& node_counter, int& max_ext_id,
bool count_only)
{
Rc rc;
int ext_nd_id;
static Point3 point;
// Init point buffer
point[0] = point[1] = point[2] = 0.0;
bool is_3D = false;
if ( dataDimension == ECIF_3D ) {
is_3D = true;
}
// Read nof-nodes entries
while ( !infile.eof() && node_counter < nof_nodes ) {
theControlCenter->update(node_counter, GUI_UPDATE_INTERVAL);
infile >> ext_nd_id;
infile >> point[0] >> point[1];
if (is_3D) {
infile >> point[2];
}
node_counter++;
if ( max_ext_id < ext_nd_id ) {
max_ext_id = ext_nd_id;
}
// Update only counter etc.
//
if ( count_only ) {
meshBoundingBox.extendByPoint(point);
// Add node to the model
//
} else {
rc = model->addMeshNode(node_counter - 1, ext_nd_id, point);
}
} // while not eof()
// Model dimension can now be set!
//
if ( !count_only ) {
modelDimension = findMeshModelDimension();
}
return ECIF_OK;
}
// Find ELMER element code for an Fidad element
bool
InputFidap::setElementType(FidapElementGroupInfo& gi)
{
int base = 200;
gi.fidap_reorder = NULL;
switch (gi.fidap_geometry) {
case 0:
if ( dataDimension == ECIF_3D ) base = 400; break;
case 1: base = 400; break;
case 2: base = 300; break;
case 3: base = 800; break;
case 4: base = 700; break;
case 5: base = 500; break;
default:
return false;
}
int type = base + gi.nofNodes;
// Types needing specific reordering or mapping to
// "lower" level types
if (type == 203) {
gi.fidap_reorder = fidapReorderTable[fidapReorderTableIndex_203];
} else if (type == 510) {
gi.fidap_reorder = fidapReorderTable[fidapReorderTableIndex_510];
} else if (type >= 718 && type < 800) {
if (type == 718)
gi.fidap_reorder = fidapReorderTable[fidapReorderTableIndex_718];
type = 706;
} else if (type == 808) {
gi.fidap_reorder = fidapReorderTable[fidapReorderTableIndex_808];
} else if (type == 809) {
gi.fidap_reorder = fidapReorderTable[fidapReorderTableIndex_809];
} else if (type >= 820) {
if (type == 827)
gi.fidap_reorder = fidapReorderTable[fidapReorderTableIndex_827];
type = 820;
}
gi.elementType = type;
return true;
}
syntax highlighted by Code2HTML, v. 0.9.1