/*********************************************************************** * * 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; }