/***********************************************************************
*
* 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_inputElmer.cpp
Language: C++
Date: 17.11.98
Version: 1.00
Author(s): Martti Verho
Revisions:
Abstract: Implementation (read ELmer mesh from DB)
************************************************************************/
#include "eio_api.h"
#include "ecif_body2D.h"
#include "ecif_body3D.h"
#include "ecif_bodyElement.h"
#include "ecif_control.h"
#include "ecif_geometry.h"
#include "ecif_inputElmer.h"
#include "ecif_model.h"
#include "ecif_userinterface.h"
#include "ecif_timer.h"
extern char read_buffer[];
InputElmer::InputElmer(enum ecif_modelDimension m_dim,
ifstream& in_file, char* in_filename):
Input(m_dim, in_file, in_filename)
{
int len = strlen(infileName);
int pos = len - 1;
// Remove possible trailing path separator
while (pos > 0 ) {
if ( infileName[pos] == '/' ||
infileName[pos] == '\\'
) {
infileName[pos] = '\0';
break;
}
pos--;
}
}
#if 0
enum ecif_modelDimension
InputElmer::findMeshModelDimension() {
int info = 0;
UserInterface* gui = theControlCenter->getGui();
ModelInfo* minfo = (ModelInfo*) model->getModelInfo();
enum ecif_modelDimension dimension = minfo->dimension;
//---Init EIO
eio_init(info);
//---Find model dimension from the mesh element types
if (dimension == ECIF_ND) {
int nodeC, elementC, bndrElementC;
nodeC = elementC = bndrElementC = 0;
int nof_used_element_types = 0;
int* used_element_types = new int[MAX_NOF_ELEM_CODES];
int* used_element_type_counts = new int[MAX_NOF_ELEM_CODES];
// Read mesh info and close
eio_open_mesh(infileName, info);
if (info == -1) {
gui->errMsg(0, "Cannot read Elmer mesh header in the directory:", infileName);
return ECIF_ND;
}
eio_get_mesh_description(nodeC, elementC, bndrElementC,
nof_used_element_types,
used_element_types, used_element_type_counts, info);
eio_close_mesh(info);
// Problems for reading Elmer mesh!
if (info == -1 || nodeC <= 0 || elementC <= 0 || bndrElementC <= 0) {
gui->errMsg(0, "Cannot read Elmer mesh header description in the directory:", infileName);
return ECIF_ND;
}
// Find dimension from element types
int max_type = 0;
for (int i = 0; i < nof_used_element_types; i++) {
if (used_element_types[i] > max_type)
max_type = used_element_types[i];
}
// 2D
if (max_type >= 200 && max_type <= 500)
dimension = ECIF_2D;
// 3D
else if (max_type >= 500)
dimension = ECIF_3D;
delete[] used_element_types;
delete[] used_element_type_counts;
}
//---Close EIO
eio_close(info);
return dimension;
}
#endif
enum ecif_modelDimension
InputElmer::findMeshModelDimension() {
ecif_modelDimension dim = ECIF_ND;
ecif_modelDimension box_dim = ECIF_ND;
ecif_modelDimension elem_dim = ECIF_ND;
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;
}
// Find actual dimension
dim = findModelDimension(box_dim);
return dim;
}
//---Create and update mesh tables
//
// NOTE: Elmer mesh is processed differently compared to other
// 'external' meshes. It has its own 'processMeshFileData'-method!
//
bool
InputElmer::processMeshFileData()
{
Rc rc;
const ModelStatistics* ms = model->getModelStatistics();
//---Elmer mesh as an external mesh!
//
if ( ms->nofBodies == 0 ) {
return Input::processMeshFileData();
}
//---Elmer mesh as a model mesh
//
Timer timer;
double time, time1, time2;
//---We can allocate and create actual bulk and boundary elements elements
//model->allocateMeshBulkElements(nofInputBulkElements, nofInputBulkElements);
//rc = model->installMeshInputBulkElements();
//model->createMeshBodyTables();
//model->createMeshBodies();
//model->convertMeshBulkElementIdsExt2Int();
//model->allocateMeshBoundaryElements(nofInputBoundaryElements);
//rc = model->installMeshInputBoundaryElements();
//model->removeMeshInputElements();
UserInterface* gui = theControlCenter->getGui();
// Bulk element stuff
// ==================
MeshElementTable* bt = model->getMeshBulkElements();
//---Create BULK element connections (neighor ids, sub element indices
timer.start(); time1 = 0;
gui->showMsg("---Creating volume element connections ...");
model->findMeshElementNeighbors(bt);
time2 = timer.getLapTime(WALL_TIME); time = time2 - time1; time1 = time2;
gui->showUsedTimeMsg(time, "---Creating volume element connections", short(0), false);
//---Create bulk elmement edges
model->createMeshBulkElementEdges();
// Boundary element stuff
// ======================
MeshElementTable* bet = model->getMeshBoundaryElements();
//---Create mesh boundary element neighbors
model->findMeshElementNeighbors(bet);
//---Create boundary element edges
model->createMeshBoundaryElementEdges();
//---Finish
timer.stop();
time = timer.getEndTime(WALL_TIME);
gui->showUsedTimeMsg(time, "Creating mesh bodies and boundaries", 0, true);
return modelDimension;
}
// Read mesh (nodes, bulk and bndr elements) from the Elmer DB
//
bool
InputElmer::readMeshGeometry()
{
int info;
int bulk_element_count;
int bndr_element_count;
int node_count;
int nof_used_element_types;
int used_element_types[64];
int used_element_type_counts[64];
int input_elem_count = 0;
int actual_bulk_elem_count = 0;
int actual_bndr_elem_count = 0;
int edge_elem_count = 0;
int vrtx_elem_count = 0;
UserInterface* gui = theControlCenter->getGui();
const ModelInfo* mi = model->getModelInfo();
const ModelStatistics* ms = model->getModelStatistics();
bool model_has_geometry = (ms->nofElements > 0);
//---Init DB
eio_init(info);
if (info == -1) {
gui->errMsg(0, "WARNING: Cannot open Elmer mesh files using directory:\n\n", infileName);
return resetMeshData();
}
//---Open DB mesh data
eio_open_mesh(infileName, info);
if (info == -1) {
gui->errMsg(0, "WARNING: Cannot open Elmer mesh files using directory:\n\n", infileName);
return resetMeshData();
}
// Read mesh info
eio_get_mesh_description(node_count, bulk_element_count, bndr_element_count,
nof_used_element_types,
used_element_types, used_element_type_counts, info);
maxExternalElementId = max(bulk_element_count, bndr_element_count);
//---Delete possible old mesh data and init data
model->resetMeshData();
//---Allocate mesh tables
model->allocateMeshBodies(ms->nofBodies);
model->allocateMeshNodes(node_count, node_count);
//---Read nodes from the mesh input file
if ( ECIF_OK != readMeshNodes(node_count) ) {
return resetMeshData();
}
// Set model dimension
//
if ( !model_has_geometry ) {
modelDimension = findMeshModelDimension();
model->setModelDimension(modelDimension);
} else {
modelDimension = inputDimension;
}
//---Calculate nof "real" bulk/boundary elements
short table_index = DESC_ELEM_TYPE; // Description table column index
for (short i = 0; i < nof_used_element_types; i++) {
int elem_code = model->convertElementType(used_element_types[i]);
if ( elem_code == MEC_000 ) {
return false;
}
// Subtract elements which are not actual bulk/boundary elements
//
// NOTE: Normally we just drop vertices(2D)/edges(3D) from boundary elements
// but especially a 2D model read as 3D-BEM model needs special treatment
//
// These are bulk elements
if (
(modelDimension == ECIF_3D && MeshElementDesc[elem_code][table_index] > 500) ||
(modelDimension == ECIF_2D && MeshElementDesc[elem_code][table_index] > 300)
) {
actual_bulk_elem_count += used_element_type_counts[i];
// These are boundary elements
} else if (
(modelDimension == ECIF_3D && MeshElementDesc[elem_code][table_index] > 300) ||
(modelDimension == ECIF_2D && MeshElementDesc[elem_code][table_index] > 200)
) {
actual_bndr_elem_count += used_element_type_counts[i];
// These are edge elements
} else if ( MeshElementDesc[elem_code][table_index] > 200 ) {
edge_elem_count += used_element_type_counts[i];
// These are vertex elements
} else {
vrtx_elem_count += used_element_type_counts[i];
}
}
int nof_input_elements = 0;
if ( !model_has_geometry ) {
nof_input_elements += edge_elem_count + vrtx_elem_count;
}
if ( bulk_element_count > actual_bulk_elem_count ) {
nof_input_elements += bulk_element_count - actual_bulk_elem_count;
}
if ( nof_input_elements > 0 ) {
model->allocateMeshInputElements(nof_input_elements, maxExternalElementId);
}
// Bulk element table
// ------------------
model->allocateMeshBulkElements(actual_bulk_elem_count, maxExternalElementId);
bulkElementsAllocated = true;
//---Read volume elements from the mesh input file
if ( ECIF_OK != readMeshBulkElements() ) {
return resetMeshData();
}
model->setMeshNodes();
// NOTE: We have to construct mesh bodies already here, because boundary
// elements need to know the parent body for their parent boundary when
// they are installed into boundary-element-table
//
// NOTE: Do not convert here the bulk element ids into internal ids!
// (external bulk element ids are stored in the input in the boundary elements!)
//
model->createMeshBodyTables();
model->createMeshBodies();
// Boundary element table
// ----------------------
model->allocateMeshBoundaryElements(actual_bndr_elem_count);
bndrElementsAllocated = true;
//---Read all boundary elements from the mesh input file
if ( ECIF_OK != readMeshBoundaryElements() ) {
return resetMeshData();
}
//---Close DB connection
eio_close_mesh(info);
eio_close(info);
//---Update Gui
gui->updateModelStatistics(model);
gui->setWasUpdated("Mesh From Db");
gui->setModelHasElmerMesh();
return true;
}
bool
InputElmer::readMeshHeader()
{
return true;
}
// Read boundary elements from the Elmer DB Mesh File and store them into the model.
Rc
InputElmer::readMeshBoundaryElements()
{
UserInterface* gui = theControlCenter->getGui();
strstream strm1, strm2;
const ModelStatistics* ms = model->getModelStatistics();
bool model_has_geometry = (ms->nofElements > 0);
Rc rc;
int info;
int boundary_tag, last_boundary_tag;
int element_id;
int elem_type;
meshElementCode elem_code;
int ext_node_ids[MAX_NOF_NODES];
int ext_parent1_id, ext_parent2_id;
int int_parent1_id, int_parent2_id;
double coord[3 * MAX_NOF_NODES];
last_boundary_tag = NO_INDEX;
while (1) {
eio_get_mesh_bndry_element(element_id, boundary_tag,
ext_parent1_id, ext_parent2_id,
elem_type, ext_node_ids,
coord, info);
if (info == -1)
break;
bool add_as_boundary = true;
bool add_as_sub_element = false;
bool add_as_edge_element = false;
bool add_as_vrtx_element = false;
// These are not "real" boundary elements but
// lower level in hierachy like vertex in 2D and edge in 3D
if (modelDimension == ECIF_2D) {
switch (elem_type) {
case 101:
add_as_boundary = false;
add_as_sub_element = true;
add_as_vrtx_element = true;
default:
break;
}
} else if (modelDimension == ECIF_3D) {
switch (elem_type) {
case 101:
add_as_boundary = false;
add_as_sub_element = true;
add_as_vrtx_element = true;
break;
case 202:
case 203:
add_as_boundary = false;
add_as_sub_element = true;
add_as_edge_element = true;
break;
default:
break;
}
}
// Possibly the second parent is the correct one
if ( ext_parent1_id <= 0 ) {
ext_parent1_id = ext_parent2_id;
ext_parent2_id = NO_INDEX;
}
// We prefer NO-INDEX as the no-parent indicator
if (ext_parent1_id <= 0) {
ext_parent1_id = NO_INDEX;
}
if (ext_parent2_id <= 0) {
ext_parent2_id = NO_INDEX;
}
elem_code = model->convertElementType(elem_type);
bool is_added;
if ( add_as_boundary ) {
rc = model->addMeshBoundaryElement(boundary_tag,
elem_code,
ext_parent1_id, ext_parent2_id,
ext_node_ids,
is_added);
if ( rc != ECIF_OK ) {
strm1 << "***ERROR when reading mesh boundary elements!" << ends;
strm2 << "Could not insert boundary element " << element_id << ends;
gui->showMsg(strm1.str());
gui->showMsg(strm2.str());
return rc;
}
} // is bndr_element
// We must add the mesh element pending, defined just by node ids, and
// then add the nodes later to proper mesh element (edge or vertex)
// NOTE: This is used only if we have model geometry available, so that
// we can pick the correct body element
// We cannot *create* the bodyelement here, because we do not know whose
// subelement it is!
//
if ( add_as_sub_element ) {
if ( model_has_geometry ) {
static BodyElement* se = NULL;
if ( last_boundary_tag != boundary_tag ) {
se = model->getBodyElementByBoundaryTag(boundary_tag);
}
if ( se != NULL ) {
se->addPendingMeshElementAsNodes(elem_type, (int*)ext_node_ids);
}
} else {
rc = model->addMeshInputElement(elem_type, element_id,
NO_INDEX, boundary_tag,
ext_node_ids);
if ( rc != ECIF_OK ) {
strm1 << "***ERROR when reading mesh boundary elements!" << ends;
strm2 << "Could not add mesh edge/vetrex element " << element_id << ends;
gui->showMsg(strm1.str());
gui->showMsg(strm2.str());
return rc;
}
if ( add_as_edge_element ) {
nofInputEdgeElements++;
} else {
nofInputVertexElements++;
}
}
}
// Update last boundary tag
if ( last_boundary_tag != boundary_tag ) {
last_boundary_tag = boundary_tag;
}
}
return ECIF_OK;
}
// Read an element from the Elmer Mesh File and store it into the model.
Rc
InputElmer::readMeshBulkElements()
{
UserInterface* gui = theControlCenter->getGui();
strstream strm1, strm2;
Rc rc;
int info;
int body_tag;
int ext_element_id;
int ext_node_ids[MAX_NOF_NODES];
int pdofs[10];
int elem_type;
const ModelStatistics* ms = model->getModelStatistics();
bool model_has_geometry = (ms->nofElements > 0);
while (1) {
eio_get_mesh_element_conns(ext_element_id, body_tag, elem_type, pdofs, ext_node_ids, info);
if (info == -1) break;
meshElementCode elem_code = model->convertElementType(elem_type);
if ( (modelDimension == ECIF_3D && elem_type < 500) ||
(modelDimension == ECIF_2D && elem_type < 300)
) {
// This will become a boundary element and will cause a body to be created!
rc = model->addMeshInputElement(elem_type, ext_element_id,
NO_INDEX, body_tag,
ext_node_ids);
nofInputBoundaryElements++;
} else {
rc = model->addMeshBulkElement(ext_element_id, body_tag,
elem_code, ext_node_ids);
}
if (rc != ECIF_OK) {
strm1 << "***ERROR when reading bulk elements!" << ends;
strm2 << "Could not insert element " << ext_element_id << ends;
gui->showMsg(strm1.str());
gui->showMsg(strm2.str());
return rc;
}
}
return ECIF_OK;
}
// Read all nodes from the Elmer Mesh File and store them into the model
Rc
InputElmer::readMeshNodes(int nof_nodes)
{
Rc rc;
int* node_ids = new int[nof_nodes];
double* coordinates = new double[3 * nof_nodes];
int info;
eio_get_mesh_nodes(node_ids, coordinates, info);
Point3 p;
int point_position = 0;
for (int i = 0; i < nof_nodes; i++) {
double* c = coordinates + point_position;
p[0] = c[0];
p[1] = c[1];
p[2] = c[2];
rc = model->addMeshNode( node_ids[i] - 1, node_ids[i], p);
meshBoundingBox.extendByPoint(p);
if (rc != ECIF_OK)
return rc;
point_position += 3;
}
delete[] node_ids;
delete[] coordinates;
return ECIF_OK;
}
// Clean table after an error
bool
InputElmer::resetMeshData()
{
int info;
//---Close EIO
eio_close_mesh(info);
eio_close(info);
return false;
}
syntax highlighted by Code2HTML, v. 0.9.1