// -*- C++ -*- // $RCSfile: grid.C,v $ // $Revision: 1.21 $ // $Author: langer $ // $Date: 2005/07/30 20:16:08 $ /* This software was produced by NIST, an agency of the U.S. government, * and by statute is not subject to copyright in the United States. * Recipients of this software assume all responsibilities associated * with its operation, modification and maintenance. However, to * facilitate maintenance we ask that before distributing modifed * versions of this software, you first contact the authors at * oof_manager@ctcms.nist.gov. */ // general grid maintenance and repair //#include "cmdlist.h" #include "elementgroups.h" #include "formdrawer.h" #include "grid.h" #include "griditerator.h" #include "hashmesh.h" #include "mvmult.h" #include "node.h" #include "nodegroups.h" #include "parameters.h" #include "statistics.h" #include "random.h" #include "mvmd.h" #include "mvvd.h" #include #include "timer.h" // ------------------------------------------------------------ // Grid::Grid() : node(0, BlockSize(100)), interiorE(0, BlockSize(100)), boundaryE(0, BlockSize(100)), nodegroup(0), nodehash(&Node::position), elemhash(&Element::center), hash_needed(1), enhancement_(enhancement_dflt), #ifdef THERMAL fix_masters_thermal_flag(false), #endif // THERMAL fix_masters_elastic_flag(false) {} void Grid::setNelements(int Nel) { interiorE.setphysicalsize(Nel); } void Grid::setNnodes(int Nnd) { node.setphysicalsize(Nnd); elastic_dof.free_dof.setphysicalsize(2*Nnd); #ifdef THERMAL thermal_dof.free_dof.setphysicalsize(Nnd); #endif } Grid::~Grid() { // do these in reverse order, since the groups remove themselves // from the list as they're deleted. for(int i=nodegroup.capacity()-1; i>=0; i--) delete nodegroup[i]; for(int i=elementgroup.capacity()-1; i>=0; i--) delete elementgroup[i]; for(int i=0; iindex >= interiorE.capacity()) interiorE.resize(elem->index+1, (Element*) 0); if(interiorE[elem->index] != 0) { garcon()->msout << ms_error << "Duplicate element index " << elem->index << "!" << endl << ms_normal; return 0; } interiorE[elem->index] = elem; return 1; } // ------------------------------------------------------------ // void Grid::AddNode(int index, Node *newnode) { // add to node list if(index >= node.capacity()) node.resize(index+1, (Node*)0); node[index] = newnode; } // ------------------------------------------------------------ // /* Create node connectivity matrix. Two nodes are connected if they * are in a non-empty element. */ void Grid::make_connectivity() { ElementIterator iter(EI_NONEMPTY, this); Element *el; while(el = iter()) { for(int i=1; icorner.capacity(); i++) for(int j=0; jcorner[i]->index, el->corner[j]->index) = true; connectivity(el->corner[j]->index, el->corner[i]->index) = true; } } ElementIterator iter2(EI_ALL, this); while(el = iter2()) { for(int i=1; icorner.capacity(); i++) for(int j=0; jcorner[i]->index, el->corner[j]->index) = true; fullconnectivity(el->corner[j]->index, el->corner[i]->index) = true; } } } #ifdef THERMAL void Grid::make_connectivity_phi() { ElementIterator iter(EI_NONEMPTY_PHI, this); Element *el; while(el = iter()) { for(int i=1; icorner.capacity(); i++) for(int j=0; jcorner[i]->index, el->corner[j]->index) = true; connectivity_phi(el->corner[j]->index, el->corner[i]->index) = true; } } } #endif // THERMAL void Grid::reset_connectivity() { connectivity.clear(); fullconnectivity.clear(); #ifdef THERMAL connectivity_phi.clear(); #endif } // is node i connected physically to any other nodes? bool Grid::connected(int i) { if(connectivity.rows() == 0) make_connectivity(); SparseLinkIterator iter(connectivity, i); // loop over row i int j, k; bool link; while(iter(j, k, link)) if(link) return true; return false; } #ifdef THERMAL bool Grid::connected_phi(int i) { if(connectivity_phi.rows() == 0) make_connectivity_phi(); SparseLinkIterator iter(connectivity_phi, i); int j, k; bool link; while(iter(j, k, link)) if(link) return true; return false; } #endif // THERMAL //-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-// void Grid::update_node_elists() { if(elements_changed > node_elists_updated) { ++node_elists_updated; for(int j=0; jelement.resize(0); ElementIterator iter(EI_ALL, this); Element *el; while(el = iter()) { for(int i=0; icorner.capacity(); i++) el->corner[i]->element.grow(1, el); } } } //-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-// NodeGroup *Grid::getgroup(const CharString &label, const TrueFalse &create) { // look for group with given label for(int i=0; iname()) return nodegroup[i]; // construct new group if(create) { NodeGroup *newgroup = new NodeGroup(label); nodegroup.grow(1, newgroup); return newgroup; } return 0; } void Grid::showgroups() const { if(nodegroup.capacity() == 0) garcon()->msout << ms_error << " No groups!" << endl << ms_normal; else for(int i=0; imsout << " " << *nodegroup[i] << endl; } ElementGroup *Grid::getEgroup(const CharString &label, const TrueFalse &create) { // look for group with given label for(int i=0; iname()) return elementgroup[i]; // construct new group if(create) { // garcon()->msout << "creating group " << label << endl; ElementGroup *newgroup = new ElementGroup(label); elementgroup.grow(1, newgroup); return newgroup; } return 0; } void Grid::showEgroups() const { if(elementgroup.capacity() == 0) garcon()->msout << ms_error << " No groups!" << endl << ms_normal; else for(int i=0; imsout << " " << *nodegroup[i] << endl; } //-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-// // free (unfix) all nodes in all node groups void Grid::freeall_nodes_x() const { for(int i=0; ifree_x(); } void Grid::freeall_nodes_y() const { for(int i=0; ifree_y(); } #ifdef THERMAL void Grid::freeall_nodes_phi() const { for(int i=0; ifree_phi(); } #endif //-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-// // Emancipate all dof's, but leave the nodegroups marked for enslavement void Grid::emancipate_all_elastic_dofs() const { for(int i=0; ido_emancipatenodes_elastic_all(); } void Grid::emancipate_all_groups() const { for(int i=0; iemancipatenodes_all(); } // Enslave all node groups that are marked for enslavement void Grid::enslave_marked_elastic_dofs() const { for(int i=0; ido_enslavenodes_elastic_all(); } #ifdef THERMAL void Grid::emancipate_all_thermal_dofs() const { for(int i=0; ido_emancipatenodes_thermal_all(); } void Grid::enslave_marked_thermal_dofs() const { for(int i=0; ido_enslavenodes_thermal_all(); } #endif // THERMAL //-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-// // Apply distortions and forces. // apply absolute distortions (stored in nodegroups) to the nodes themselves void Grid::apply_absolute_elastic_distortion() { // The force on a node is the total force of all of that nodes // nodegroups. So the force has to be reset here, before applying // any of the groups' forces. The displacements don't accumulate // like this, so they are reset just before being applied by each // nodegroup. for(int i=0; ireset_force(); for(int i=0; iapply_absolute_elastic_distortion(); newcoords(); hash_needed = 1; } // apply all groups' incremental distortions and forces to their nodes void Grid::apply_incremental_elastic_distortion() { // increment the absolute distortions stored in the groups for(int i=0; iabsolute_force += n->incremental_force; n->absolute_distortion += n->incremental_distortion; n->absolute_shift += n->incremental_shift; } // apply the new absolute distortion apply_absolute_elastic_distortion(); } void Grid::clear_elastic_distortion() { for(int i=0; iclear_elastic_distortion(); apply_absolute_elastic_distortion(); } //-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-// #ifdef THERMAL // See the analogous elastic distortion routines above for a few more // relevant comments... void Grid::apply_absolute_thermal_distortion() { for(int i=0; ireset_surfcharge(); for(int i=0; iapply_absolute_thermal_distortion(); } void Grid::apply_incremental_thermal_distortion() { for(int i=0; iabsolute_thermaldistortion += n->incremental_thermaldistortion; } apply_absolute_thermal_distortion(); } void Grid::clear_thermal_distortion() { for(int i=0; iclear_thermal_distortion(); apply_absolute_thermal_distortion(); } #endif // THERMAL //-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-// // tell elements that the coordinates have changed. they may want to // update their stiffness matrices. void Grid::newcoords() { for(int i=0; inewcoords(); for(int i=0; inewcoords(); } // ------------------------------------------------------------ // static const MeshCoord zeroforce(0., 0.); static const MeshCoord zeroshift(0., 0.); static const TwoTwo zeromatrix; #ifdef THERMAL static const ThermalDistortion zerothermaldistortion; #endif // THERMAL void Grid::reset() { for(int i=0; ireset_displacement(1, 1); node[i]->reset_force(); #ifdef THERMAL node[i]->reset_surfcharge(); node[i]->reset_voltage(); #endif // THERMAL } for(int i=0; iabsolute_force = zeroforce; nodegroup[i]->absolute_distortion = zeromatrix; nodegroup[i]->absolute_shift = zeroshift; #ifdef THERMAL nodegroup[i]->absolute_thermaldistortion = zerothermaldistortion; #endif // THERMAL } needs_recomputed(); // so that stress and strain are recomputed ElementIterator iter(EI_ALL, this); Element *el; while(el = iter()) el->revert(); hash_needed = 1; newcoords(); } // ------------------------------------------------------------ // double Grid::enhancement_dflt = 1.0; void Grid::set_enhancement(double enh) { enhancement_ = enh; require_rehash(); } void Grid::set_enhancement_cmd(const CharString&) { // static if(grid) { grid->set_enhancement(enhancement_dflt); grid->redraw(); } } // ------------------------------------------------------------ // #ifdef DEBUG void Grid::printKlocal(ostream &os) { int ni = interiorE.capacity(); for(int i=0; iprintstiffness(os); } int nb = boundaryE.capacity(); for(int i=0; iprintstiffness(os); } } void Grid::printKii(ostream &os) { if(!Kii.dim(0)) { shufflelists_elastic(); make_stiffness(); } os << Kii.dim(0) << " " << Kii.dim(1) << endl; os << Kii; } void Grid::printKib(ostream &os) { if(!Kib.dim(0)) { shufflelists_elastic(); make_stiffness(); } os << Kib.dim(0) << " " << Kib.dim(1) << endl; os << Kib; } void Grid::printKbb(ostream &os) { if(!Kbb.dim(0)) { shufflelists_elastic(); make_stiffness(); } os << Kbb.dim(0) << " " << Kbb.dim(1) << endl; os << Kbb; } #endif // DEBUG void Grid::postscript(FILE *psfile) { fprintf(psfile,"%%!Postscript from oof\n"); fprintf(psfile,"/el {newpath moveto lineto lineto stroke} def\n"); int ni = interiorE.capacity(); for(int i=0; i= 0 ; ic--) fprintf(psfile,"%f %f ", interiorE[i]->corner[ic]->position().x, interiorE[i]->corner[ic]->position().y); fprintf(psfile,"el\n"); } int nb = boundaryE.capacity(); for(int i=0; i= 0 ; ic--) fprintf(psfile,"%f %f ", boundaryE[i]->corner[ic]->position().x, boundaryE[i]->corner[ic]->position().y); fprintf(psfile,"el\n"); } } Rectangle Grid::query_extreme_pos() const { if(node.capacity() < 2) return Rectangle(0, 1, 0, 1); Rectangle range(node[0]->position(enhancement()), node[1]->position(enhancement())); for (int i=0; iposition(enhancement())); return range; } // ------------------------------------------------------------- // Node *Grid::findNode(const MeshCoord &where) { rehash(); return nodehash.find(where); } Element *Grid::findElement(const MeshCoord &where) { rehash(); return elemhash.find(where); } void Grid::rehash() { if(!hash_needed) return; Rectangle range(query_extreme_pos()); double aspect = (range.xmax-range.xmin)/(range.ymax-range.ymin); int nx = int(0.5*sqrt((double) node.capacity())*aspect); int ny = int(0.5*sqrt((double) node.capacity())/aspect); nodehash.setsize(nx, ny, range); elemhash.setsize(nx, ny, range); for(int i=0; iunselect(); for(int i=0; iunselect(); } void Grid::selectallelements() const { for(int i=0; iselect(); for(int i=0; iselect(); } void Grid::toggleselect() const { for(int i=0; itoggleselect(); for(int i=0; itoggleselect(); } void Grid::selectelement(int which) const { for(int i=0; iindex == which) { interiorE[i]->select(); return; } for(int i=0; iindex == which) { boundaryE[i]->select(); return; } } void Grid::selectrandomelements(double prob) const { for(int i=0; iselect(); else interiorE[i]->unselect(); for(int i=0; iselect(); else boundaryE[i]->unselect(); } void Grid::selectshape(const Shape &shape) const { for(int i=0; icenter())) interiorE[i]->select(); for(int i=0; icenter())) boundaryE[i]->select(); } // ---------------------------------------------------------------- // void Grid::selectallnodes() const { for(int i=0; iselect(); } void Grid::selectshape_nodes(const Shape &shape) const { for(int i=0; iposition())) node[i]->select(); } void Grid::unselectallnodes() const { for(int i=0; iunselect(); } // ---------------------------------------------------------------- // int Grid::mutate() { int count = 0; // number of elements mutated Element *el; ElementIterator iter(EI_ALL, this); Interrupter stop; while((el = iter()) && !stop()) { if(el->mutate()) { el->setstiffness(); count++; } } // redraw(); // redraw is done in higher level routine return count; } void Grid::needs_recomputed() { Element *el; ElementIterator iter(EI_ALL, this); while(el = iter()) { el->not_current(); } } void Grid::complete_equilibrate(int use_global) { int mutants = 1; Interrupter stopnow; while(mutants && !stopnow()) { int equilibrated = equilibrate(use_global); redraw(); if(garcon()->graphics()) XFlush(fl_get_display()); if(!equilibrated) return; // bail out if doesn't converge mutants = mutate(); garcon()->msout << ms_info << mutants << " element" << (mutants==1?"":"s") << " mutated." << endl << ms_normal; } } StressStrainStat Grid::stress_statistics(Iterator &itel) const { Element *el; StressStrainStat stats; while(el = itel()) { stats.include(el->stresstensor(), el->original_area()); } return stats; } StressStrainStat Grid::strain_statistics(Iterator &itel) const { Element *el; StressStrainStat stats; while(el = itel()) { stats.include(el->total_straintensor(), el->original_area()); } return stats; } //-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-// DoFset::DoFset() : fixed_dof(0, BlockSize(100)), free_dof(0, BlockSize(100)), inactive_dof(0, BlockSize(10)) {} DoFset::~DoFset() { for(int i=0; idump(os); } void Grid::nodedump(ostream &os) const { os << "*** Nodes ***" << endl; for(int i=0; idump(os); } #ifdef THERMAL void Grid::dofdump(ostream &os) const { os << "*** thermal dofs ***" << endl; thermal_dof.dump(os); } #else // !THERMAL void Grid::dofdump(ostream&) const {} #endif // THERMAL void DoFset::dump(ostream &os) const { os << "------ free" << endl; for(int i=0; idump(os, ""); os << "------ fixed" << endl; for(int i=0; idump(os, ""); os << "------ inactive" << endl; for(int i=0; idump(os, ""); } #endif // DEBUG #include "hashmesh.C"