$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 #include "libmesh/libmesh_config.h" 00019 #ifdef LIBMESH_ENABLE_VSMOOTHER 00020 00021 // C++ includes 00022 #include <time.h> // for clock_t, clock() 00023 #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC 00024 #include <cmath> 00025 #include <iomanip> 00026 00027 // Local includes 00028 #include "libmesh/mesh_smoother_vsmoother.h" 00029 #include "libmesh/mesh_tools.h" 00030 #include "libmesh/elem.h" 00031 #include "libmesh/unstructured_mesh.h" 00032 #include "libmesh/utility.h" 00033 00034 namespace libMesh 00035 { 00036 00037 // Optimization at -O2 or greater seem to break Intel's icc. So if we are 00038 // being compiled with icc let's dumb-down the optimizations for this file 00039 #ifdef __INTEL_COMPILER 00040 # pragma optimize ( "", off ) 00041 #endif 00042 00043 // Member functions for the Variational Smoother 00044 VariationalMeshSmoother::VariationalMeshSmoother(UnstructuredMesh& mesh, 00045 double theta, 00046 unsigned miniter, 00047 unsigned maxiter, 00048 unsigned miniterBC) : 00049 MeshSmoother(mesh), 00050 _percent_to_move(1), 00051 _dist_norm(0.), 00052 _adapt_data(NULL), 00053 _dim(mesh.mesh_dimension()), 00054 _miniter(miniter), 00055 _maxiter(maxiter), 00056 _miniterBC(miniterBC), 00057 _metric(UNIFORM), 00058 _adaptive_func(NONE), 00059 _theta(theta), 00060 _generate_data(false), 00061 _n_nodes(0), 00062 _n_cells(0), 00063 _n_hanging_edges(0), 00064 _area_of_interest(NULL) 00065 {} 00066 00067 00068 00069 00070 VariationalMeshSmoother::VariationalMeshSmoother(UnstructuredMesh& mesh, 00071 std::vector<float>* adapt_data, 00072 double theta, 00073 unsigned miniter, 00074 unsigned maxiter, 00075 unsigned miniterBC, 00076 double percent_to_move) : 00077 MeshSmoother(mesh), 00078 _percent_to_move(percent_to_move), 00079 _dist_norm(0.), 00080 _adapt_data(adapt_data), 00081 _dim(mesh.mesh_dimension()), 00082 _miniter(miniter), 00083 _maxiter(maxiter), 00084 _miniterBC(miniterBC), 00085 _metric(UNIFORM), 00086 _adaptive_func(CELL), 00087 _theta(theta), 00088 _generate_data(false), 00089 _n_nodes(0), 00090 _n_cells(0), 00091 _n_hanging_edges(0), 00092 _area_of_interest(NULL) 00093 {} 00094 00095 00096 00097 VariationalMeshSmoother::VariationalMeshSmoother(UnstructuredMesh& mesh, 00098 const UnstructuredMesh* area_of_interest, 00099 std::vector<float>* adapt_data, 00100 double theta, 00101 unsigned miniter, 00102 unsigned maxiter, 00103 unsigned miniterBC, 00104 double percent_to_move) : 00105 MeshSmoother(mesh), 00106 _percent_to_move(percent_to_move), 00107 _dist_norm(0.), 00108 _adapt_data(adapt_data), 00109 _dim(mesh.mesh_dimension()), 00110 _miniter(miniter), 00111 _maxiter(maxiter), 00112 _miniterBC(miniterBC), 00113 _metric(UNIFORM), 00114 _adaptive_func(CELL), 00115 _theta(theta), 00116 _generate_data(false), 00117 _n_nodes(0), 00118 _n_cells(0), 00119 _n_hanging_edges(0), 00120 _area_of_interest(area_of_interest) 00121 {} 00122 00123 00124 00125 double VariationalMeshSmoother::smooth(unsigned int) 00126 { 00127 // If the log file is already open, for example on subsequent calls 00128 // to smooth() on the same object, we'll just keep writing to it, 00129 // otherwise we'll open it... 00130 if (!_logfile.is_open()) 00131 _logfile.open("smoother.out"); 00132 00133 int 00134 me = _metric, 00135 gr = _generate_data ? 0 : 1, 00136 adp = _adaptive_func, 00137 miniter = _miniter, 00138 maxiter = _maxiter, 00139 miniterBC = _miniterBC; 00140 00141 double theta = _theta; 00142 00143 // Metric file name 00144 std::string metric_filename = "smoother.metric"; 00145 if (gr == 0 && me > 1) 00146 { 00147 // grid filename 00148 std::string grid_filename = "smoother.grid"; 00149 00150 // generate metric from initial mesh (me = 2,3) 00151 metr_data_gen(grid_filename, metric_filename, me); 00152 } 00153 00154 // Initialize the _n_nodes and _n_cells member variables 00155 this->_n_nodes = _mesh.n_nodes(); 00156 this->_n_cells = _mesh.n_active_elem(); 00157 00158 // Initialize the _n_hanging_edges member variable 00159 MeshTools::find_hanging_nodes_and_parents(_mesh, _hanging_nodes); 00160 this->_n_hanging_edges = 00161 cast_int<dof_id_type>(_hanging_nodes.size()); 00162 00163 std::vector<int> 00164 mask(_n_nodes), 00165 edges(2*_n_hanging_edges), 00166 mcells(_n_cells), 00167 hnodes(_n_hanging_edges); 00168 00169 Array2D<double> R(_n_nodes, _dim); 00170 Array2D<int> cells(_n_cells, 3*_dim + _dim%2); 00171 Array3D<double> H(_n_cells, _dim, _dim); 00172 00173 // initial grid 00174 int vms_err = readgr(R, mask, cells, mcells, edges, hnodes); 00175 if (vms_err < 0) 00176 { 00177 _logfile << "Error reading input mesh file" << std::endl; 00178 return _dist_norm; 00179 } 00180 00181 if (me > 1) 00182 vms_err = readmetr(metric_filename, H); 00183 00184 if (vms_err < 0) 00185 { 00186 _logfile << "Error reading metric file" << std::endl; 00187 return _dist_norm; 00188 } 00189 00190 std::vector<int> iter(4); 00191 iter[0] = miniter; 00192 iter[1] = maxiter; 00193 iter[2] = miniterBC; 00194 00195 // grid optimization 00196 _logfile << "Starting Grid Optimization" << std::endl; 00197 clock_t ticks1 = clock(); 00198 full_smooth(R, mask, cells, mcells, edges, hnodes, theta, iter, me, H, adp, gr); 00199 clock_t ticks2 = clock(); 00200 _logfile << "full_smooth took (" 00201 << ticks2 00202 << "-" 00203 << ticks1 00204 << ")/" 00205 << CLOCKS_PER_SEC 00206 << " = " 00207 << static_cast<double>(ticks2-ticks1)/static_cast<double>(CLOCKS_PER_SEC) 00208 << " seconds" 00209 << std::endl; 00210 00211 // save result 00212 _logfile << "Saving Result" << std::endl; 00213 writegr(R); 00214 00215 libmesh_assert_greater (_dist_norm, 0); 00216 return _dist_norm; 00217 } 00218 00219 00220 00221 // save grid 00222 int VariationalMeshSmoother::writegr(const Array2D<double>& R) 00223 { 00224 libMesh::out << "Starting writegr" << std::endl; 00225 00226 // Adjust nodal coordinates to new positions 00227 { 00228 MeshBase::node_iterator it = _mesh.nodes_begin(); 00229 const MeshBase::node_iterator end = _mesh.nodes_end(); 00230 00231 libmesh_assert_equal_to(_dist_norm, 0.); 00232 _dist_norm = 0; 00233 for (int i=0; it!=end; ++it) 00234 { 00235 double total_dist = 0.; 00236 00237 // For each node set its X Y [Z] coordinates 00238 for (unsigned int j=0; j<_dim; j++) 00239 { 00240 // Get a reference to the node 00241 Node& node = *(*it); 00242 00243 double distance = R[i][j] - node(j); 00244 00245 // Save the squares of the distance 00246 total_dist += Utility::pow<2>(distance); 00247 00248 node(j) += distance*_percent_to_move; 00249 } 00250 00251 libmesh_assert_greater_equal (total_dist, 0.); 00252 00253 // Add the distance this node moved to the global distance 00254 _dist_norm += total_dist; 00255 00256 i++; 00257 } 00258 00259 // Relative "error" 00260 _dist_norm = std::sqrt(_dist_norm/_mesh.n_nodes()); 00261 } 00262 00263 libMesh::out << "Finished writegr" << std::endl; 00264 return 0; 00265 } 00266 00267 00268 00269 // reading grid from input file 00270 int VariationalMeshSmoother::readgr(Array2D<double>& R, 00271 std::vector<int>& mask, 00272 Array2D<int>& cells, 00273 std::vector<int>& mcells, 00274 std::vector<int>& edges, 00275 std::vector<int>& hnodes) 00276 { 00277 libMesh::out << "Sarting readgr" << std::endl; 00278 // add error messages where format can be inconsistent 00279 00280 // Find the boundary nodes 00281 std::vector<bool> on_boundary; 00282 MeshTools::find_boundary_nodes(_mesh, on_boundary); 00283 00284 // Grab node coordinates and set mask 00285 { 00286 MeshBase::const_node_iterator it = _mesh.nodes_begin(); 00287 const MeshBase::const_node_iterator end = _mesh.nodes_end(); 00288 00289 // Only compute the node to elem map once 00290 std::vector<std::vector<const Elem*> > nodes_to_elem_map; 00291 MeshTools::build_nodes_to_elem_map(_mesh, nodes_to_elem_map); 00292 00293 for (int i=0; it != end; ++it) 00294 { 00295 // Get a reference to the node 00296 Node& node = *(*it); 00297 00298 // For each node grab its X Y [Z] coordinates 00299 for (unsigned int j=0; j<_dim; j++) 00300 R[i][j] = node(j); 00301 00302 // Set the Proper Mask 00303 // Internal nodes are 0 00304 // Immovable boundary nodes are 1 00305 // Movable boundary nodes are 2 00306 if (on_boundary[i]) 00307 { 00308 // Only look for sliding edge nodes in 2D 00309 if (_dim == 2) 00310 { 00311 // Find all the nodal neighbors... that is the nodes directly connected 00312 // to this node through one edge 00313 std::vector<const Node*> neighbors; 00314 MeshTools::find_nodal_neighbors(_mesh, node, nodes_to_elem_map, neighbors); 00315 00316 std::vector<const Node*>::const_iterator ne = neighbors.begin(); 00317 std::vector<const Node*>::const_iterator ne_end = neighbors.end(); 00318 00319 // Grab the x,y coordinates 00320 Real x = node(0); 00321 Real y = node(1); 00322 00323 // Theta will represent the atan2 angle (meaning with the proper quadrant in mind) 00324 // of the neighbor node in a system where the current node is at the origin 00325 Real theta = 0; 00326 std::vector<Real> thetas; 00327 00328 // Calculate the thetas 00329 for (; ne != ne_end; ne++) 00330 { 00331 const Node& neighbor = *(*ne); 00332 00333 // Note that the x and y values of this node are subtracted off 00334 // this centers the system around this node 00335 theta = atan2(neighbor(1)-y, neighbor(0)-x); 00336 00337 // Save it for later 00338 thetas.push_back(theta); 00339 } 00340 00341 // Assume the node is immovable... then prove otherwise 00342 mask[i] = 1; 00343 00344 // Search through neighbor nodes looking for two that form a straight line with this node 00345 for (unsigned int a=0; a<thetas.size()-1; a++) 00346 { 00347 // Only try each pairing once 00348 for (unsigned int b=a+1; b<thetas.size(); b++) 00349 { 00350 // Find if the two neighbor nodes angles are 180 degrees (pi) off of eachother (withing a tolerance) 00351 // In order to make this a true movable boundary node... the two that forma straight line with 00352 // it must also be on the boundary 00353 if (on_boundary[neighbors[a]->id()] && 00354 on_boundary[neighbors[b]->id()] && 00355 ( 00356 (std::abs(thetas[a] - (thetas[b] + (libMesh::pi))) < .001) || 00357 (std::abs(thetas[a] - (thetas[b] - (libMesh::pi))) < .001) 00358 ) 00359 ) 00360 { 00361 // if ((*(*it))(1) > 0.25 || (*(*it))(0) > .7 || (*(*it))(0) < .01) 00362 mask[i] = 2; 00363 } 00364 00365 } 00366 } 00367 } 00368 else // In 3D set all boundary nodes to be fixed 00369 mask[i] = 1; 00370 } 00371 else 00372 mask[i] = 0; // Internal Node 00373 00374 // libMesh::out << "Node: " << i << " Mask: " << mask[i] << std::endl; 00375 i++; 00376 } 00377 } 00378 00379 // Grab the connectivity 00380 // FIXME: Generalize this! 00381 { 00382 MeshBase::const_element_iterator it = _mesh.active_elements_begin(); 00383 const MeshBase::const_element_iterator end = _mesh.active_elements_end(); 00384 00385 for (int i=0; it != end; ++it) 00386 { 00387 const Elem* elem = *it; 00388 00389 // Keep track of the number of nodes 00390 // there must be 6 for 2D 00391 // 10 for 3D 00392 // If there are actually less than that -1 must be used 00393 // to fill out the rest 00394 int num = 0; 00395 /* 00396 int num_necessary = 0; 00397 00398 if (_dim == 2) 00399 num_necessary = 6; 00400 else 00401 num_necessary = 10; 00402 */ 00403 00404 if (_dim == 2) 00405 { 00406 switch (elem->n_vertices()) 00407 { 00408 // Grab nodes that do exist 00409 case 3: // Tri 00410 for (unsigned int k=0; k<elem->n_vertices(); k++) 00411 cells[i][k] = elem->node(k); 00412 00413 num = elem->n_vertices(); 00414 break; 00415 00416 case 4: // Quad 4 00417 cells[i][0] = elem->node(0); 00418 cells[i][1] = elem->node(1); 00419 cells[i][2] = elem->node(3); // Note that 2 and 3 are switched! 00420 cells[i][3] = elem->node(2); 00421 num = 4; 00422 break; 00423 00424 default: 00425 libmesh_error_msg("Unknown number of vertices = " << elem->n_vertices()); 00426 } 00427 } 00428 else 00429 { 00430 // Grab nodes that do exist 00431 switch (elem->n_vertices()) 00432 { 00433 // Tet 4 00434 case 4: 00435 for (unsigned int k=0; k<elem->n_vertices(); k++) 00436 cells[i][k] = elem->node(k); 00437 num = elem->n_vertices(); 00438 break; 00439 00440 // Hex 8 00441 case 8: 00442 cells[i][0] = elem->node(0); 00443 cells[i][1] = elem->node(1); 00444 cells[i][2] = elem->node(3); // Note that 2 and 3 are switched! 00445 cells[i][3] = elem->node(2); 00446 00447 cells[i][4] = elem->node(4); 00448 cells[i][5] = elem->node(5); 00449 cells[i][6] = elem->node(7); // Note that 6 and 7 are switched! 00450 cells[i][7] = elem->node(6); 00451 num=8; 00452 break; 00453 00454 default: 00455 libmesh_error_msg("Unknown 3D element with = " << elem->n_vertices() << " vertices."); 00456 } 00457 } 00458 00459 // Fill in the rest with -1 00460 for (int j=num; j<static_cast<int>(cells[i].size()); j++) 00461 cells[i][j] = -1; 00462 00463 // Mask it with 0 to state that this is an active element 00464 // FIXME: Could be something other than zero 00465 mcells[i] = 0; 00466 i++; 00467 } 00468 } 00469 00470 // Grab hanging node connectivity 00471 { 00472 std::map<dof_id_type, std::vector<dof_id_type> >::iterator 00473 it = _hanging_nodes.begin(), 00474 end = _hanging_nodes.end(); 00475 00476 for (int i=0; it!=end; it++) 00477 { 00478 libMesh::out << "Parent 1: " << (it->second)[0] << std::endl; 00479 libMesh::out << "Parent 2: " << (it->second)[1] << std::endl; 00480 libMesh::out << "Hanging Node: " << it->first << std::endl << std::endl; 00481 00482 // First Parent 00483 edges[2*i] = (it->second)[1]; 00484 00485 // Second Parent 00486 edges[2*i+1] = (it->second)[0]; 00487 00488 // Hanging Node 00489 hnodes[i] = it->first; 00490 00491 i++; 00492 } 00493 } 00494 libMesh::out << "Finished readgr" << std::endl; 00495 00496 return 0; 00497 } 00498 00499 00500 00501 // Read Metrics 00502 int VariationalMeshSmoother::readmetr(std::string name, 00503 Array3D<double>& H) 00504 { 00505 std::ifstream infile(name.c_str()); 00506 std::string dummy; 00507 00508 for (dof_id_type i=0; i<_n_cells; i++) 00509 for (unsigned j=0; j<_dim; j++) 00510 { 00511 for (unsigned k=0; k<_dim; k++) 00512 infile >> H[i][j][k]; 00513 00514 // Read to end of line and discard 00515 std::getline(infile, dummy); 00516 } 00517 00518 return 0; 00519 } 00520 00521 00522 00523 // Stolen from ErrorVector! 00524 float VariationalMeshSmoother::adapt_minimum() const 00525 { 00526 float min = 1.e30; 00527 00528 for (unsigned int i=0; i<_adapt_data->size(); i++) 00529 { 00530 // Only positive (or zero) values in the error vector 00531 libmesh_assert_greater_equal ((*_adapt_data)[i], 0.); 00532 min = std::min (min, (*_adapt_data)[i]); 00533 } 00534 00535 // ErrorVectors are for positive values 00536 libmesh_assert_greater_equal (min, 0.); 00537 00538 return min; 00539 } 00540 00541 00542 00543 void VariationalMeshSmoother::adjust_adapt_data() 00544 { 00545 // For convenience 00546 const UnstructuredMesh & aoe_mesh = *_area_of_interest; 00547 std::vector<float>& adapt_data = *_adapt_data; 00548 00549 float min = adapt_minimum(); 00550 00551 MeshBase::const_element_iterator el = _mesh.elements_begin(); 00552 const MeshBase::const_element_iterator end_el = _mesh.elements_end(); 00553 00554 MeshBase::const_element_iterator aoe_el = aoe_mesh.elements_begin(); 00555 const MeshBase::const_element_iterator aoe_end_el = aoe_mesh.elements_end(); 00556 00557 // Counter to keep track of which spot in adapt_data we're looking at 00558 for (int i=0; el!=end_el; el++) 00559 { 00560 // Only do this for active elements 00561 if (adapt_data[i]) 00562 { 00563 Point centroid = (*el)->centroid(); 00564 bool in_aoe = false; 00565 00566 // See if the elements centroid lies in the aoe mesh 00567 // for (aoe_el=aoe_mesh.elements_begin(); aoe_el != aoe_end_el; ++aoe_el) 00568 // { 00569 if ((*aoe_el)->contains_point(centroid)) 00570 in_aoe = true; 00571 // } 00572 00573 // If the element is not in the area of interest... then set 00574 // it's adaptivity value to the minimum. 00575 if (!in_aoe) 00576 adapt_data[i] = min; 00577 } 00578 i++; 00579 } 00580 } 00581 00582 00583 00584 // Read Adaptivity 00585 int VariationalMeshSmoother::read_adp(std::vector<double>& afun) 00586 { 00587 std::vector<float>& adapt_data = *_adapt_data; 00588 00589 if (_area_of_interest) 00590 adjust_adapt_data(); 00591 00592 std::size_t m = adapt_data.size(); 00593 00594 std::size_t j =0 ; 00595 for (std::size_t i=0; i<m; i++) 00596 if (adapt_data[i] != 0) 00597 { 00598 afun[j] = adapt_data[i]; 00599 j++; 00600 } 00601 00602 return 0; 00603 } 00604 00605 00606 00607 double VariationalMeshSmoother::jac3(double x1, 00608 double y1, 00609 double z1, 00610 double x2, 00611 double y2, 00612 double z2, 00613 double x3, 00614 double y3, 00615 double z3) 00616 { 00617 return x1*(y2*z3 - y3*z2) + y1*(z2*x3 - z3*x2) + z1*(x2*y3 - x3*y2); 00618 } 00619 00620 00621 00622 double VariationalMeshSmoother::jac2(double x1, 00623 double y1, 00624 double x2, 00625 double y2) 00626 { 00627 return x1*y2 - x2*y1; 00628 } 00629 00630 00631 00632 // BasisA determines matrix H^(-T)Q on one Jacobian matrix 00633 int VariationalMeshSmoother::basisA(Array2D<double>& Q, 00634 int nvert, 00635 const std::vector<double>& K, 00636 const Array2D<double>& H, 00637 int me) 00638 { 00639 Array2D<double> U(_dim, nvert); 00640 00641 // Some useful constants 00642 const double 00643 sqrt3 = std::sqrt(3.), 00644 sqrt6 = std::sqrt(6.); 00645 00646 if (_dim == 2) 00647 { 00648 if (nvert == 4) 00649 { 00650 // quad 00651 U[0][0] = -(1-K[1]); 00652 U[0][1] = (1-K[1]); 00653 U[0][2] = -K[1]; 00654 U[0][3] = K[1]; 00655 00656 U[1][0] = -(1-K[0]); 00657 U[1][1] = -K[0]; 00658 U[1][2] = (1-K[0]); 00659 U[1][3] = K[0]; 00660 } 00661 else if (nvert == 3) 00662 { 00663 // tri 00664 // for right target triangle 00665 // U[0][0] = -1.; U[1][0] = -1.; 00666 // U[0][1] = 1.; U[1][1] = 0.; 00667 // U[0][2] = 0.; U[1][2] = 1.; 00668 00669 // for regular triangle 00670 U[0][0] = -1.; 00671 U[0][1] = 1.; 00672 U[0][2] = 0; 00673 00674 U[1][0] = -1./sqrt3; 00675 U[1][1] = -1./sqrt3; 00676 U[1][2] = 2./sqrt3; 00677 } 00678 else if (nvert == 6) 00679 { 00680 // curved triangle 00681 U[0][0] = -3*(1-K[0]-K[1]*0.5)+(K[0]-0.5*K[1])+K[1]; 00682 U[0][1] = -(1-K[0]-K[1]*0.5)+(K[0]-0.5*K[1])*3-K[1]; 00683 U[0][2] = 0; 00684 U[0][3] = K[1]*4; 00685 U[0][4] = -4*K[1]; 00686 U[0][5] = 4*(1-K[0]-K[1]*0.5)-4*(K[0]-0.5*K[1]); 00687 00688 U[1][0] = (1-K[2]-K[3]*0.5)*(-1.5)+(K[2]-0.5*K[3])*(0.5)+K[3]*(0.5); 00689 U[1][1] = (1-K[2]-K[3]*0.5)*(0.5)+(K[2]-0.5*K[3])*(-1.5)+K[3]*(0.5); 00690 U[1][2] = (1-K[2]-K[3]*0.5)*(-1)+(K[2]-0.5*K[3])*(-1)+K[3]*(3); 00691 U[1][3] = (K[2]-0.5*K[3])*(4.)+K[3]*(-2.); 00692 U[1][4] = (1-K[2]-K[3]*0.5)*(4.)+K[3]*(-2.); 00693 U[1][5] = (1-K[2]-K[3]*0.5)*(-2.)+(K[2]-0.5*K[3])*(-2.); 00694 } 00695 else 00696 libmesh_error_msg("Invalid nvert = " << nvert); 00697 } 00698 00699 if (_dim == 3) 00700 { 00701 if (nvert == 8) 00702 { 00703 // hex 00704 U[0][0] = -(1-K[0])*(1-K[1]); 00705 U[0][1] = (1-K[0])*(1-K[1]); 00706 U[0][2] = -K[0]*(1-K[1]); 00707 U[0][3] = K[0]*(1-K[1]); 00708 U[0][4] = -(1-K[0])*K[1]; 00709 U[0][5] = (1-K[0])*K[1]; 00710 U[0][6] = -K[0]*K[1]; 00711 U[0][7] = K[0]*K[1]; 00712 00713 U[1][0] = -(1-K[2])*(1-K[3]); 00714 U[1][1] = -K[2]*(1-K[3]); 00715 U[1][2] = (1-K[2])*(1-K[3]); 00716 U[1][3] = K[2]*(1-K[3]); 00717 U[1][4] = -(1-K[2])*K[3]; 00718 U[1][5] = -K[2]*K[3]; 00719 U[1][6] = (1-K[2])*K[3]; 00720 U[1][7] = K[2]*K[3]; 00721 00722 U[2][0] = -(1-K[4])*(1-K[5]); 00723 U[2][1] = -K[4]*(1-K[5]); 00724 U[2][2] = -(1-K[4])*K[5]; 00725 U[2][3] = -K[4]*K[5]; 00726 U[2][4] = (1-K[4])*(1-K[5]); 00727 U[2][5] = K[4]*(1-K[5]); 00728 U[2][6] = (1-K[4])*K[5]; 00729 U[2][7] = K[4]*K[5]; 00730 } 00731 else if (nvert == 4) 00732 { 00733 // linear tetr 00734 // for regular reference tetrahedron 00735 U[0][0] = -1; 00736 U[0][1] = 1; 00737 U[0][2] = 0; 00738 U[0][3] = 0; 00739 00740 U[1][0] = -1./sqrt3; 00741 U[1][1] = -1./sqrt3; 00742 U[1][2] = 2./sqrt3; 00743 U[1][3] = 0; 00744 00745 U[2][0] = -1./sqrt6; 00746 U[2][1] = -1./sqrt6; 00747 U[2][2] = -1./sqrt6; 00748 U[2][3] = 3./sqrt6; 00749 00750 // for right corner reference tetrahedron 00751 // U[0][0] = -1; U[1][0] = -1; U[2][0] = -1; 00752 // U[0][1] = 1; U[1][1] = 0; U[2][1] = 0; 00753 // U[0][2] = 0; U[1][2] = 1; U[2][2] = 0; 00754 // U[0][3] = 0; U[1][3] = 0; U[2][3] = 1; 00755 } 00756 else if (nvert == 6) 00757 { 00758 // prism 00759 // for regular triangle in the prism base 00760 U[0][0] = -1+K[0]; 00761 U[0][1] = 1-K[0]; 00762 U[0][2] = 0; 00763 U[0][3] = -K[0]; 00764 U[0][4] = K[0]; 00765 U[0][5] = 0; 00766 00767 U[1][0] = 0.5*(-1+K[1]); 00768 U[1][1] = 0.5*(-1+K[1]); 00769 U[1][2] = (1-K[1]); 00770 U[1][3] = -0.5*K[1]; 00771 U[1][4] = -0.5*K[1]; 00772 U[1][5] = K[1]; 00773 00774 U[2][0] = -1. + K[2] + 0.5*K[3]; 00775 U[2][1] = -K[2] + 0.5*K[3]; 00776 U[2][2] = -K[3]; 00777 U[2][3] = 1 - K[2] - 0.5*K[3]; 00778 U[2][4] = K[2] - 0.5*K[3]; 00779 U[2][5] = K[3]; 00780 } 00781 else if (nvert == 10) 00782 { 00783 // quad tetr 00784 U[0][0] = -3.*(1 - K[0] - 0.5*K[1] - K[2]/3.) + (K[0] - 0.5*K[1] - K[2]/3.) + (K[1] - K[2]/3.) + K[2]; 00785 U[0][1] = -1.*(1 - K[0] - 0.5*K[1] - K[2]/3.) + 3.*(K[0] - 0.5*K[1] - K[2]/3.) - (K[1] - K[2]/3.) - K[2]; 00786 U[0][2] = 0.; 00787 U[0][3] = 0.; 00788 U[0][4] = 4.*(K[1] - K[2]/3.); 00789 U[0][5] = -4.*(K[1] - K[2]/3.); 00790 U[0][6] = 4.*(1. - K[0] - 0.5*K[1] - K[2]/3.) - 4.*(K[0] - 0.5*K[1] - K[2]/3.); 00791 U[0][7] = 4.*K[2]; 00792 U[0][8] = 0.; 00793 U[0][9] = -4.*K[2]; 00794 00795 U[1][0] = -1.5*(1. - K[3] - K[4]*0.5 - K[5]/3.) + 0.5*(K[3] - 0.5*K[4] - K[5]/3.) + 0.5*(K[4] - K[5]/3.) + 0.5*K[5]; 00796 U[1][1] = 0.5*(1. - K[3] - K[4]*0.5 - K[5]/3.) - 1.5*(K[3] - 0.5*K[4] - K[5]/3.) + 0.5*(K[4] - K[5]/3.) + 0.5*K[5]; 00797 U[1][2] = -1.*(1. - K[3] - K[4]*0.5 - K[5]/3.) - (K[3] - 0.5*K[4] - K[5]/3.) + 3.*(K[4] - K[5]/3.) - K[5]; 00798 U[1][3] = 0.; 00799 U[1][4] = 4.*( K[3] - 0.5*K[4] - K[5]/3.) - 2.*(K[4] - K[5]/3.); 00800 U[1][5] = 4.*(1. - K[3] - 0.5*K[4] - K[5]/3.) - 2.*(K[4] - K[5]/3.); 00801 U[1][6] = -2.*(1. - K[3] - 0.5*K[4] - K[5]/3.) - 2.*(K[3] - 0.5*K[4] - K[5]/3.); 00802 U[1][7] = -2.*K[5]; 00803 U[1][8] = 4.*K[5]; 00804 U[1][9] = -2.*K[5]; 00805 00806 U[2][0] = -(1. - K[6] - 0.5*K[7] - K[8]/3.) + (K[6] - 0.5*K[7] - K[8]/3.)/3. + (K[7] - K[8]/3.)/3. + K[8]/3.; 00807 U[2][1] = (1. - K[6] - 0.5*K[7] - K[8]/3.)/3. - (K[6] - 0.5*K[7] - K[8]/3.) + (K[7] - K[8]/3.)/3. + K[8]/3.; 00808 U[2][2] = (1. - K[6] - 0.5*K[7] - K[8]/3.)/3. + (K[6] - 0.5*K[7] - K[8]/3.)/3. - (K[7] - K[8]/3.) + K[8]/3.; 00809 U[2][3] = -(1. - K[6] - 0.5*K[7] - K[8]/3.) - (K[6] - 0.5*K[7] - K[8]/3.) - (K[7] - K[8]/3.) + 3.*K[8]; 00810 U[2][4] = -4.*(K[6] - K[7]*0.5 - K[8]/3.)/3. - 4.*(K[7] - K[8]/3.)/3.; 00811 U[2][5] = -4.*(1. - K[6] - K[7]*0.5 - K[8]/3.)/3. - 4.*( K[7] - K[8]/3.)/3.; 00812 U[2][6] = -4.*(1. - K[6] - K[7]*0.5 - K[8]/3.)/3. - 4.*(K[6] - 0.5*K[7] - K[8]/3.)/3.; 00813 U[2][7] = 4.*(K[6] - K[7]*0.5 - K[8]/3.) - 4.*K[8]/3.; 00814 U[2][8] = 4.*(K[7] - K[8]/3.) - 4.*K[8]/3.; 00815 U[2][9] = 4.*(1. - K[6] - K[7]*0.5 - K[8]/3.) - 4.*K[8]/3.; 00816 } 00817 else 00818 libmesh_error_msg("Invalid nvert = " << nvert); 00819 } 00820 00821 if (me == 1) 00822 Q = U; 00823 00824 else 00825 { 00826 for (unsigned i=0; i<_dim; i++) 00827 for (int j=0; j<nvert; j++) 00828 { 00829 Q[i][j] = 0; 00830 for (unsigned k=0; k<_dim; k++) 00831 Q[i][j] += H[k][i]*U[k][j]; 00832 } 00833 } 00834 00835 return 0; 00836 } 00837 00838 00839 00840 // Specify adaptive function 00841 void VariationalMeshSmoother::adp_renew(const Array2D<double>& R, 00842 const Array2D<int>& cells, 00843 std::vector<double>& afun, 00844 int adp) 00845 { 00846 // evaluates given adaptive function on the provided mesh 00847 if (adp < 0) 00848 { 00849 for (dof_id_type i=0; i<_n_cells; i++) 00850 { 00851 double 00852 x = 0., 00853 y = 0., 00854 z = 0.; 00855 int nvert = 0; 00856 00857 while (cells[i][nvert] >= 0) 00858 { 00859 x += R[cells[i][nvert]][0]; 00860 y += R[cells[i][nvert]][1]; 00861 if (_dim == 3) 00862 z += R[cells[i][nvert]][2]; 00863 nvert++; 00864 } 00865 00866 // adaptive function, cell based 00867 afun[i] = 5.*(x+y+z); 00868 } 00869 } 00870 00871 else if (adp > 0) 00872 { 00873 for (dof_id_type i=0; i<_n_nodes; i++) 00874 { 00875 double z = 0; 00876 for (unsigned j=0; j<_dim; j++) 00877 z += R[i][j]; 00878 00879 // adaptive function, node based 00880 afun[i] = 5*std::sin(R[i][0]); 00881 } 00882 } 00883 } 00884 00885 00886 00887 // Preprocess mesh data and control smoothing/untangling iterations 00888 void VariationalMeshSmoother::full_smooth(Array2D<double>& R, 00889 const std::vector<int>& mask, 00890 const Array2D<int>& cells, 00891 const std::vector<int>& mcells, 00892 const std::vector<int>& edges, 00893 const std::vector<int>& hnodes, 00894 double w, 00895 const std::vector<int>& iter, 00896 int me, 00897 const Array3D<double>& H, 00898 int adp, 00899 int gr) 00900 { 00901 // Control the amount of print statements in this funcion 00902 int msglev = 1; 00903 00904 dof_id_type afun_size = 0; 00905 00906 // Adaptive function is on cells 00907 if (adp < 0) 00908 afun_size = _n_cells; 00909 00910 // Adaptive function is on nodes 00911 else if (adp > 0) 00912 afun_size = _n_nodes; 00913 00914 std::vector<double> afun(afun_size); 00915 std::vector<int> maskf(_n_nodes); 00916 std::vector<double> Gamma(_n_cells); 00917 00918 if (msglev >= 1) 00919 _logfile << "N=" << _n_nodes 00920 << " ncells=" << _n_cells 00921 << " nedges=" << _n_hanging_edges 00922 << std::endl; 00923 00924 00925 // Boundary node counting 00926 int NBN=0; 00927 for (dof_id_type i=0; i<_n_nodes; i++) 00928 if (mask[i] == 2 || mask[i] == 1) 00929 NBN++; 00930 00931 if (NBN > 0) 00932 { 00933 if (msglev >= 1) 00934 _logfile << "# of Boundary Nodes=" << NBN << std::endl; 00935 00936 NBN=0; 00937 for (dof_id_type i=0; i<_n_nodes; i++) 00938 if (mask[i] == 2) 00939 NBN++; 00940 00941 if (msglev >= 1) 00942 _logfile << "# of moving Boundary Nodes=" << NBN << std::endl; 00943 } 00944 00945 for (dof_id_type i=0; i<_n_nodes; i++) 00946 { 00947 if ((mask[i]==1) || (mask[i]==2)) 00948 maskf[i] = 1; 00949 else 00950 maskf[i] = 0; 00951 } 00952 00953 // determination of min jacobian 00954 double vol, Vmin; 00955 double qmin = minq(R, cells, mcells, me, H, vol, Vmin); 00956 00957 if (me > 1) 00958 vol = 1.; 00959 00960 if (msglev >= 1) 00961 _logfile << "vol=" << vol 00962 << " qmin=" << qmin 00963 << " min volume = " << Vmin 00964 << std::endl; 00965 00966 // compute max distortion measure over all cells 00967 double epsilon = 1.e-9; 00968 double eps = qmin < 0 ? std::sqrt(epsilon*epsilon+0.004*qmin*qmin*vol*vol) : epsilon; 00969 double emax = maxE(R, cells, mcells, me, H, vol, eps, w, Gamma, qmin); 00970 00971 if (msglev >= 1) 00972 _logfile << " emax=" << emax << std::endl; 00973 00974 // unfolding/smoothing 00975 00976 // iteration tolerance 00977 double Enm1 = 1.; 00978 00979 // read adaptive function from file 00980 if (adp*gr != 0) 00981 read_adp(afun); 00982 00983 { 00984 int 00985 counter = 0, 00986 ii = 0; 00987 00988 while (((qmin <= 0) || (counter < iter[0]) || (std::abs(emax-Enm1) > 1e-3)) && 00989 (ii < iter[1]) && 00990 (counter < iter[1])) 00991 { 00992 libmesh_assert_less (counter, iter[1]); 00993 00994 Enm1 = emax; 00995 00996 if ((ii >= 0) && (ii % 2 == 0)) 00997 { 00998 if (qmin < 0) 00999 eps = std::sqrt(epsilon*epsilon + 0.004*qmin*qmin*vol*vol); 01000 else 01001 eps = epsilon; 01002 } 01003 01004 int ladp = adp; 01005 01006 if ((qmin <= 0) || (counter < ii)) 01007 ladp = 0; 01008 01009 // update adaptation function before each iteration 01010 if ((ladp != 0) && (gr == 0)) 01011 adp_renew(R, cells, afun, adp); 01012 01013 double Jk = minJ(R, maskf, cells, mcells, eps, w, me, H, vol, edges, hnodes, 01014 msglev, Vmin, emax, qmin, ladp, afun); 01015 01016 if (qmin > 0) 01017 counter++; 01018 else 01019 ii++; 01020 01021 if (msglev >= 1) 01022 _logfile << "niter=" << counter 01023 << ", qmin*G/vol=" << qmin 01024 << ", Vmin=" << Vmin 01025 << ", emax=" << emax 01026 << ", Jk=" << Jk 01027 << ", Enm1=" << Enm1 01028 << std::endl; 01029 } 01030 } 01031 01032 // BN correction - 2D only! 01033 epsilon = 1.e-9; 01034 if (NBN > 0) 01035 for (int counter=0; counter<iter[2]; counter++) 01036 { 01037 // update adaptation function before each iteration 01038 if ((adp != 0) && (gr == 0)) 01039 adp_renew(R, cells, afun, adp); 01040 01041 double Jk = minJ_BC(R, mask, cells, mcells, eps, w, me, H, vol, msglev, Vmin, emax, qmin, adp, afun, NBN); 01042 01043 if (msglev >= 1) 01044 _logfile << "NBC niter=" << counter 01045 << ", qmin*G/vol=" << qmin 01046 << ", Vmin=" << Vmin 01047 << ", emax=" << emax 01048 << std::endl; 01049 01050 // Outrageous Enm1 to make sure we hit this at least once 01051 Enm1 = 99999; 01052 01053 // Now that we've moved the boundary nodes (or not) we need to resmoooth 01054 for (int j=0; j<iter[1]; j++) 01055 { 01056 if (std::abs(emax-Enm1) < 1e-2) 01057 break; 01058 01059 // Save off the error from the previous smoothing step 01060 Enm1 = emax; 01061 01062 // update adaptation function before each iteration 01063 if ((adp != 0) && (gr == 0)) 01064 adp_renew(R, cells, afun, adp); 01065 01066 Jk = minJ(R, maskf, cells, mcells, eps, w, me, H, vol, edges, hnodes, msglev, Vmin, emax, qmin, adp, afun); 01067 01068 if (msglev >= 1) 01069 _logfile << " Re-smooth: niter=" << j 01070 << ", qmin*G/vol=" << qmin 01071 << ", Vmin=" << Vmin 01072 << ", emax=" << emax 01073 << ", Jk=" << Jk 01074 << std::endl; 01075 } 01076 01077 if (msglev >= 1) 01078 _logfile << "NBC smoothed niter=" << counter 01079 << ", qmin*G/vol=" << qmin 01080 << ", Vmin=" << Vmin 01081 << ", emax=" << emax 01082 << std::endl; 01083 } 01084 } 01085 01086 01087 01088 // Determines the values of maxE_theta 01089 double VariationalMeshSmoother::maxE(Array2D<double>& R, 01090 const Array2D<int>& cells, 01091 const std::vector<int>& mcells, 01092 int me, 01093 const Array3D<double>& H, 01094 double v, 01095 double epsilon, 01096 double w, 01097 std::vector<double>& Gamma, 01098 double& qmin) 01099 { 01100 Array2D<double> Q(3, 3*_dim + _dim%2); 01101 std::vector<double> K(9); 01102 01103 double 01104 gemax = -1.e32, 01105 vmin = 1.e32; 01106 01107 for (dof_id_type ii=0; ii<_n_cells; ii++) 01108 if (mcells[ii] >= 0) 01109 { 01110 // Final value of E will be saved in Gamma at the end of this loop 01111 double E = 0.; 01112 01113 if (_dim == 2) 01114 { 01115 if (cells[ii][3] == -1) 01116 { 01117 // tri 01118 basisA(Q, 3, K, H[ii], me); 01119 01120 std::vector<double> a1(3), a2(3); 01121 for (int k=0; k<2; k++) 01122 for (int l=0; l<3; l++) 01123 { 01124 a1[k] += Q[k][l]*R[cells[ii][l]][0]; 01125 a2[k] += Q[k][l]*R[cells[ii][l]][1]; 01126 } 01127 01128 double det = jac2(a1[0], a1[1], a2[0], a2[1]); 01129 double tr = 0.5*(a1[0]*a1[0] + a2[0]*a2[0] + a1[1]*a1[1] + a2[1]*a2[1]); 01130 double chi = 0.5*(det+std::sqrt(det*det+epsilon*epsilon)); 01131 E = (1-w)*tr/chi + 0.5*w*(v + det*det/v)/chi; 01132 01133 if (E > gemax) 01134 gemax = E; 01135 if (vmin > det) 01136 vmin = det; 01137 01138 } 01139 else if (cells[ii][4] == -1) 01140 { 01141 // quad 01142 for (int i=0; i<2; i++) 01143 { 01144 K[0] = i; 01145 for (int j=0; j<2; j++) 01146 { 01147 K[1] = j; 01148 basisA(Q, 4, K, H[ii], me); 01149 01150 std::vector<double> a1(3), a2(3); 01151 for (int k=0; k<2; k++) 01152 for (int l=0; l<4; l++) 01153 { 01154 a1[k] += Q[k][l]*R[cells[ii][l]][0]; 01155 a2[k] += Q[k][l]*R[cells[ii][l]][1]; 01156 } 01157 01158 double det = jac2(a1[0],a1[1],a2[0],a2[1]); 01159 double tr = 0.5*(a1[0]*a1[0] + a2[0]*a2[0] + a1[1]*a1[1] + a2[1]*a2[1]); 01160 double chi = 0.5*(det+std::sqrt(det*det+epsilon*epsilon)); 01161 E += 0.25*((1-w)*tr/chi + 0.5*w*(v + det*det/v)/chi); 01162 01163 if (vmin > det) 01164 vmin = det; 01165 } 01166 } 01167 01168 if (E > gemax) 01169 gemax = E; 01170 } 01171 else 01172 { 01173 // quad tri 01174 for (int i=0; i<3; i++) 01175 { 01176 K[0] = i*0.5; 01177 int k = i/2; 01178 K[1] = static_cast<double>(k); 01179 01180 for (int j=0; j<3; j++) 01181 { 01182 K[2] = j*0.5; 01183 k = j/2; 01184 K[3] = static_cast<double>(k); 01185 01186 basisA(Q, 6, K, H[ii], me); 01187 01188 std::vector<double> a1(3), a2(3); 01189 for (int k=0; k<2; k++) 01190 for (int l=0; l<6; l++) 01191 { 01192 a1[k] += Q[k][l]*R[cells[ii][l]][0]; 01193 a2[k] += Q[k][l]*R[cells[ii][l]][1]; 01194 } 01195 01196 double det = jac2(a1[0],a1[1],a2[0],a2[1]); 01197 double sigma = 1./24.; 01198 01199 if (i==j) 01200 sigma = 1./12.; 01201 01202 double tr = 0.5*(a1[0]*a1[0] + a2[0]*a2[0] + a1[1]*a1[1] + a2[1]*a2[1]); 01203 double chi = 0.5*(det + std::sqrt(det*det + epsilon*epsilon)); 01204 E += sigma*((1-w)*tr/chi + 0.5*w*(v + det*det/v)/chi); 01205 if (vmin > det) 01206 vmin = det; 01207 } 01208 } 01209 01210 if (E > gemax) 01211 gemax = E; 01212 } 01213 } 01214 01215 if (_dim == 3) 01216 { 01217 if (cells[ii][4] == -1) 01218 { 01219 // tetr 01220 basisA(Q, 4, K, H[ii], me); 01221 01222 std::vector<double> a1(3), a2(3), a3(3); 01223 for (int k=0; k<3; k++) 01224 for (int l=0; l<4; l++) 01225 { 01226 a1[k] += Q[k][l]*R[cells[ii][l]][0]; 01227 a2[k] += Q[k][l]*R[cells[ii][l]][1]; 01228 a3[k] += Q[k][l]*R[cells[ii][l]][2]; 01229 } 01230 01231 double det = jac3(a1[0], a1[1], a1[2], 01232 a2[0], a2[1], a2[2], 01233 a3[0], a3[1], a3[2]); 01234 double tr = 0.; 01235 for (int k=0; k<3; k++) 01236 tr += (a1[k]*a1[k] + a2[k]*a2[k] + a3[k]*a3[k])/3.; 01237 01238 double chi = 0.5*(det+std::sqrt(det*det+epsilon*epsilon)); 01239 E = (1-w)*pow(tr,1.5)/chi + 0.5*w*(v + det*det/v)/chi; 01240 01241 if (E > gemax) 01242 gemax = E; 01243 01244 if (vmin > det) 01245 vmin = det; 01246 } 01247 else if (cells[ii][6] == -1) 01248 { 01249 // prism 01250 for (int i=0; i<2; i++) 01251 { 01252 K[0] = i; 01253 for (int j=0; j<2; j++) 01254 { 01255 K[1] = j; 01256 for (int k=0; k<3; k++) 01257 { 01258 K[2] = 0.5*static_cast<double>(k); 01259 K[3] = static_cast<double>(k % 2); 01260 basisA(Q, 6, K, H[ii], me); 01261 01262 std::vector<double> a1(3), a2(3), a3(3); 01263 for (int kk=0; kk<3; kk++) 01264 for (int ll=0; ll<6; ll++) 01265 { 01266 a1[kk] += Q[kk][ll]*R[cells[ii][ll]][0]; 01267 a2[kk] += Q[kk][ll]*R[cells[ii][ll]][1]; 01268 a3[kk] += Q[kk][ll]*R[cells[ii][ll]][2]; 01269 } 01270 01271 double det = jac3(a1[0], a1[1], a1[2], 01272 a2[0], a2[1], a2[2], 01273 a3[0], a3[1], a3[2]); 01274 double tr = 0; 01275 for (int kk=0; kk<3; kk++) 01276 tr += (a1[kk]*a1[kk] + a2[kk]*a2[kk] + a3[kk]*a3[kk])/3.; 01277 01278 double chi = 0.5*(det+std::sqrt(det*det+epsilon*epsilon)); 01279 E += ((1-w)*pow(tr,1.5)/chi + 0.5*w*(v + det*det/v)/chi)/12.; 01280 if (vmin > det) 01281 vmin = det; 01282 } 01283 } 01284 } 01285 01286 if (E > gemax) 01287 gemax = E; 01288 } 01289 else if (cells[ii][8] == -1) 01290 { 01291 // hex 01292 for (int i=0; i<2; i++) 01293 { 01294 K[0] = i; 01295 for (int j=0; j<2; j++) 01296 { 01297 K[1] = j; 01298 for (int k=0; k<2; k++) 01299 { 01300 K[2] = k; 01301 for (int l=0; l<2; l++) 01302 { 01303 K[3] = l; 01304 for (int m=0; m<2; m++) 01305 { 01306 K[4] = m; 01307 for (int nn=0; nn<2; nn++) 01308 { 01309 K[5] = nn; 01310 basisA(Q, 8, K, H[ii], me); 01311 01312 std::vector<double> a1(3), a2(3), a3(3); 01313 for (int kk=0; kk<3; kk++) 01314 for (int ll=0; ll<8; ll++) 01315 { 01316 a1[kk] += Q[kk][ll]*R[cells[ii][ll]][0]; 01317 a2[kk] += Q[kk][ll]*R[cells[ii][ll]][1]; 01318 a3[kk] += Q[kk][ll]*R[cells[ii][ll]][2]; 01319 } 01320 01321 double det = jac3(a1[0], a1[1], a1[2], 01322 a2[0], a2[1], a2[2], 01323 a3[0], a3[1], a3[2]); 01324 double sigma = 0.; 01325 01326 if ((i==nn) && (j==l) && (k==m)) 01327 sigma = 1./27.; 01328 01329 if (((i==nn) && (j==l) && (k!=m)) || 01330 ((i==nn) && (j!=l) && (k==m)) || 01331 ((i!=nn) && (j==l) && (k==m))) 01332 sigma = 1./54.; 01333 01334 if (((i==nn) && (j!=l) && (k!=m)) || 01335 ((i!=nn) && (j!=l) && (k==m)) || 01336 ((i!=nn) && (j==l) && (k!=m))) 01337 sigma = 1./108.; 01338 01339 if ((i!=nn) && (j!=l) && (k!=m)) 01340 sigma = 1./216.; 01341 01342 double tr = 0; 01343 for (int kk=0; kk<3; kk++) 01344 tr += (a1[kk]*a1[kk] + a2[kk]*a2[kk] + a3[kk]*a3[kk])/3.; 01345 01346 double chi = 0.5*(det+std::sqrt(det*det + epsilon*epsilon)); 01347 E += ((1-w)*pow(tr,1.5)/chi + 0.5*w*(v + det*det/v)/chi)*sigma; 01348 if (vmin > det) 01349 vmin = det; 01350 } 01351 } 01352 } 01353 } 01354 } 01355 } 01356 if (E > gemax) 01357 gemax = E; 01358 } 01359 else 01360 { 01361 // quad tetr 01362 for (int i=0; i<4; i++) 01363 { 01364 for (int j=0; j<4; j++) 01365 { 01366 for (int k=0; k<4; k++) 01367 { 01368 switch (i) 01369 { 01370 case 0: 01371 K[0] = 0; 01372 K[1] = 0; 01373 K[2] = 0; 01374 break; 01375 case 1: 01376 K[0] = 1; 01377 K[1] = 0; 01378 K[2] = 0; 01379 break; 01380 case 2: 01381 K[0] = 0.5; 01382 K[1] = 1; 01383 K[2] = 0; 01384 break; 01385 case 3: 01386 K[0] = 0.5; 01387 K[1] = 1./3.; 01388 K[2] = 1; 01389 break; 01390 } 01391 01392 switch (j) 01393 { 01394 case 0: 01395 K[3] = 0; 01396 K[4] = 0; 01397 K[5] = 0; 01398 break; 01399 case 1: 01400 K[3] = 1; 01401 K[4] = 0; 01402 K[5] = 0; 01403 break; 01404 case 2: 01405 K[3] = 0.5; 01406 K[4] = 1; 01407 K[5] = 0; 01408 break; 01409 case 3: 01410 K[3] = 0.5; 01411 K[4] = 1./3.; 01412 K[5] = 1; 01413 break; 01414 } 01415 01416 switch (k) 01417 { 01418 case 0: 01419 K[6] = 0; 01420 K[7] = 0; 01421 K[8] = 0; 01422 break; 01423 case 1: 01424 K[6] = 1; 01425 K[7] = 0; 01426 K[8] = 0; 01427 break; 01428 case 2: 01429 K[6] = 0.5; 01430 K[7] = 1; 01431 K[8] = 0; 01432 break; 01433 case 3: 01434 K[6] = 0.5; 01435 K[7] = 1./3.; 01436 K[8] = 1; 01437 break; 01438 } 01439 01440 basisA(Q, 10, K, H[ii], me); 01441 01442 std::vector<double> a1(3), a2(3), a3(3); 01443 for (int kk=0; kk<3; kk++) 01444 for (int ll=0; ll<10; ll++) 01445 { 01446 a1[kk] += Q[kk][ll]*R[cells[ii][ll]][0]; 01447 a2[kk] += Q[kk][ll]*R[cells[ii][ll]][1]; 01448 a3[kk] += Q[kk][ll]*R[cells[ii][ll]][2]; 01449 } 01450 01451 double det = jac3(a1[0], a1[1], a1[2], 01452 a2[0], a2[1], a2[2], 01453 a3[0], a3[1], a3[2]); 01454 double sigma = 0.; 01455 01456 if ((i==j) && (j==k)) 01457 sigma = 1./120.; 01458 else if ((i==j) || (j==k) || (i==k)) 01459 sigma = 1./360.; 01460 else 01461 sigma = 1./720.; 01462 01463 double tr = 0; 01464 for (int kk=0; kk<3; kk++) 01465 tr += (a1[kk]*a1[kk] + a2[kk]*a2[kk] + a3[kk]*a3[kk])/3.; 01466 01467 double chi = 0.5*(det+std::sqrt(det*det+epsilon*epsilon)); 01468 E += ((1-w)*pow(tr,1.5)/chi + 0.5*w*(v+det*det/v)/chi)*sigma; 01469 if (vmin > det) 01470 vmin = det; 01471 } 01472 } 01473 } 01474 01475 if (E > gemax) 01476 gemax = E; 01477 } 01478 } 01479 Gamma[ii] = E; 01480 } 01481 01482 qmin = vmin; 01483 01484 return gemax; 01485 } 01486 01487 01488 01489 // Compute min Jacobian determinant (minq), min cell volume (Vmin), and average cell volume (vol). 01490 double VariationalMeshSmoother::minq(const Array2D<double>& R, 01491 const Array2D<int>& cells, 01492 const std::vector<int>& mcells, 01493 int me, 01494 const Array3D<double>& H, 01495 double& vol, 01496 double& Vmin) 01497 { 01498 std::vector<double> K(9); 01499 Array2D<double> Q(3, 3*_dim + _dim%2); 01500 01501 double v = 0; 01502 double vmin = 1.e32; 01503 double gqmin = 1.e32; 01504 01505 for (dof_id_type ii=0; ii<_n_cells; ii++) 01506 if (mcells[ii] >= 0) 01507 { 01508 if (_dim == 2) 01509 { 01510 // 2D 01511 if (cells[ii][3] == -1) 01512 { 01513 // tri 01514 basisA(Q, 3, K, H[ii], me); 01515 01516 std::vector<double> a1(3), a2(3); 01517 for (int k=0; k<2; k++) 01518 for (int l=0; l<3; l++) 01519 { 01520 a1[k] += Q[k][l]*R[cells[ii][l]][0]; 01521 a2[k] += Q[k][l]*R[cells[ii][l]][1]; 01522 } 01523 01524 double det = jac2(a1[0],a1[1],a2[0],a2[1]); 01525 if (gqmin > det) 01526 gqmin = det; 01527 01528 if (vmin > det) 01529 vmin = det; 01530 01531 v += det; 01532 } 01533 else if (cells[ii][4] == -1) 01534 { 01535 // quad 01536 double vcell = 0.; 01537 for (int i=0; i<2; i++) 01538 { 01539 K[0] = i; 01540 for (int j=0; j<2; j++) 01541 { 01542 K[1] = j; 01543 basisA(Q, 4, K, H[ii], me); 01544 01545 std::vector<double> a1(3), a2(3); 01546 for (int k=0; k<2; k++) 01547 for (int l=0; l<4; l++) 01548 { 01549 a1[k] += Q[k][l]*R[cells[ii][l]][0]; 01550 a2[k] += Q[k][l]*R[cells[ii][l]][1]; 01551 } 01552 01553 double det = jac2(a1[0],a1[1],a2[0],a2[1]); 01554 if (gqmin > det) 01555 gqmin = det; 01556 01557 v += 0.25*det; 01558 vcell += 0.25*det; 01559 } 01560 } 01561 if (vmin > vcell) 01562 vmin = vcell; 01563 } 01564 else 01565 { 01566 // quad tri 01567 double vcell = 0.; 01568 for (int i=0; i<3; i++) 01569 { 01570 K[0] = i*0.5; 01571 int k = i/2; 01572 K[1] = static_cast<double>(k); 01573 01574 for (int j=0; j<3; j++) 01575 { 01576 K[2] = j*0.5; 01577 k = j/2; 01578 K[3] = static_cast<double>(k); 01579 basisA(Q, 6, K, H[ii], me); 01580 01581 std::vector<double> a1(3), a2(3); 01582 for (int k=0; k<2; k++) 01583 for (int l=0; l<6; l++) 01584 { 01585 a1[k] += Q[k][l]*R[cells[ii][l]][0]; 01586 a2[k] += Q[k][l]*R[cells[ii][l]][1]; 01587 } 01588 01589 double det = jac2(a1[0], a1[1], a2[0], a2[1]); 01590 if (gqmin > det) 01591 gqmin = det; 01592 01593 double sigma = 1./24.; 01594 if (i == j) 01595 sigma = 1./12.; 01596 01597 v += sigma*det; 01598 vcell += sigma*det; 01599 } 01600 } 01601 if (vmin > vcell) 01602 vmin = vcell; 01603 } 01604 } 01605 if (_dim == 3) 01606 { 01607 // 3D 01608 if (cells[ii][4] == -1) 01609 { 01610 // tetr 01611 basisA(Q, 4, K, H[ii], me); 01612 01613 std::vector<double> a1(3), a2(3), a3(3); 01614 for (int k=0; k<3; k++) 01615 for (int l=0; l<4; l++) 01616 { 01617 a1[k] += Q[k][l]*R[cells[ii][l]][0]; 01618 a2[k] += Q[k][l]*R[cells[ii][l]][1]; 01619 a3[k] += Q[k][l]*R[cells[ii][l]][2]; 01620 } 01621 01622 double det = jac3(a1[0], a1[1], a1[2], 01623 a2[0], a2[1], a2[2], 01624 a3[0], a3[1], a3[2]); 01625 01626 if (gqmin > det) 01627 gqmin = det; 01628 01629 if (vmin > det) 01630 vmin = det; 01631 v += det; 01632 } 01633 else if (cells[ii][6] == -1) 01634 { 01635 // prism 01636 double vcell = 0.; 01637 for (int i=0; i<2; i++) 01638 { 01639 K[0] = i; 01640 for (int j=0; j<2; j++) 01641 { 01642 K[1] = j; 01643 01644 for (int k=0; k<3; k++) 01645 { 01646 K[2] = 0.5*k; 01647 K[3] = static_cast<double>(k%2); 01648 basisA(Q, 6, K, H[ii], me); 01649 01650 std::vector<double> a1(3), a2(3), a3(3); 01651 for (int kk=0; kk<3; kk++) 01652 for (int ll=0; ll<6; ll++) 01653 { 01654 a1[kk] += Q[kk][ll]*R[cells[ii][ll]][0]; 01655 a2[kk] += Q[kk][ll]*R[cells[ii][ll]][1]; 01656 a3[kk] += Q[kk][ll]*R[cells[ii][ll]][2]; 01657 } 01658 01659 double det = jac3(a1[0], a1[1], a1[2], 01660 a2[0], a2[1], a2[2], 01661 a3[0], a3[1], a3[2]); 01662 if (gqmin > det) 01663 gqmin = det; 01664 01665 double sigma = 1./12.; 01666 v += sigma*det; 01667 vcell += sigma*det; 01668 } 01669 } 01670 } 01671 if (vmin > vcell) 01672 vmin = vcell; 01673 } 01674 else if (cells[ii][8] == -1) 01675 { 01676 // hex 01677 double vcell = 0.; 01678 for (int i=0; i<2; i++) 01679 { 01680 K[0] = i; 01681 for (int j=0; j<2; j++) 01682 { 01683 K[1] = j; 01684 for (int k=0; k<2; k++) 01685 { 01686 K[2] = k; 01687 for (int l=0; l<2; l++) 01688 { 01689 K[3] = l; 01690 for (int m=0; m<2; m++) 01691 { 01692 K[4] = m; 01693 for (int nn=0; nn<2; nn++) 01694 { 01695 K[5] = nn; 01696 basisA(Q, 8, K, H[ii], me); 01697 01698 std::vector<double> a1(3), a2(3), a3(3); 01699 for (int kk=0; kk<3; kk++) 01700 for (int ll=0; ll<8; ll++) 01701 { 01702 a1[kk] += Q[kk][ll]*R[cells[ii][ll]][0]; 01703 a2[kk] += Q[kk][ll]*R[cells[ii][ll]][1]; 01704 a3[kk] += Q[kk][ll]*R[cells[ii][ll]][2]; 01705 } 01706 01707 double det = jac3(a1[0], a1[1], a1[2], 01708 a2[0], a2[1], a2[2], 01709 a3[0], a3[1], a3[2]); 01710 01711 if (gqmin > det) 01712 gqmin = det; 01713 01714 double sigma = 0.; 01715 01716 if ((i==nn) && (j==l) && (k==m)) 01717 sigma = 1./27.; 01718 01719 if (((i==nn) && (j==l) && (k!=m)) || 01720 ((i==nn) && (j!=l) && (k==m)) || 01721 ((i!=nn) && (j==l) && (k==m))) 01722 sigma = 1./54.; 01723 01724 if (((i==nn) && (j!=l) && (k!=m)) || 01725 ((i!=nn) && (j!=l) && (k==m)) || 01726 ((i!=nn) && (j==l) && (k!=m))) 01727 sigma = 1./108.; 01728 01729 if ((i!=nn) && (j!=l) && (k!=m)) 01730 sigma = 1./216.; 01731 01732 v += sigma*det; 01733 vcell += sigma*det; 01734 } 01735 } 01736 } 01737 } 01738 } 01739 } 01740 01741 if (vmin > vcell) 01742 vmin = vcell; 01743 } 01744 else 01745 { 01746 // quad tetr 01747 double vcell = 0.; 01748 for (int i=0; i<4; i++) 01749 { 01750 for (int j=0; j<4; j++) 01751 { 01752 for (int k=0; k<4; k++) 01753 { 01754 switch (i) 01755 { 01756 case 0: 01757 K[0] = 0; 01758 K[1] = 0; 01759 K[2] = 0; 01760 break; 01761 01762 case 1: 01763 K[0] = 1; 01764 K[1] = 0; 01765 K[2] = 0; 01766 break; 01767 01768 case 2: 01769 K[0] = 0.5; 01770 K[1] = 1; 01771 K[2] = 0; 01772 break; 01773 01774 case 3: 01775 K[0] = 0.5; 01776 K[1] = 1./3.; 01777 K[2] = 1; 01778 break; 01779 01780 } 01781 switch (j) 01782 { 01783 case 0: 01784 K[3] = 0; 01785 K[4] = 0; 01786 K[5] = 0; 01787 break; 01788 01789 case 1: 01790 K[3] = 1; 01791 K[4] = 0; 01792 K[5] = 0; 01793 break; 01794 01795 case 2: 01796 K[3] = 0.5; 01797 K[4] = 1; 01798 K[5] = 0; 01799 break; 01800 01801 case 3: 01802 K[3] = 0.5; 01803 K[4] = 1./3.; 01804 K[5] = 1; 01805 break; 01806 01807 } 01808 switch (k) 01809 { 01810 case 0: 01811 K[6] = 0; 01812 K[7] = 0; 01813 K[8] = 0; 01814 break; 01815 01816 case 1: 01817 K[6] = 1; 01818 K[7] = 0; 01819 K[8] = 0; 01820 break; 01821 01822 case 2: 01823 K[6] = 0.5; 01824 K[7] = 1; 01825 K[8] = 0; 01826 break; 01827 01828 case 3: 01829 K[6] = 0.5; 01830 K[7] = 1./3.; 01831 K[8] = 1; 01832 break; 01833 } 01834 01835 basisA(Q, 10, K, H[ii], me); 01836 01837 std::vector<double> a1(3), a2(3), a3(3); 01838 for (int kk=0; kk<3; kk++) 01839 for (int ll=0; ll<10; ll++) 01840 { 01841 a1[kk] += Q[kk][ll]*R[cells[ii][ll]][0]; 01842 a2[kk] += Q[kk][ll]*R[cells[ii][ll]][1]; 01843 a3[kk] += Q[kk][ll]*R[cells[ii][ll]][2]; 01844 } 01845 01846 double det = jac3(a1[0], a1[1], a1[2], 01847 a2[0], a2[1], a2[2], 01848 a3[0], a3[1], a3[2]); 01849 if (gqmin > det) 01850 gqmin = det; 01851 01852 double sigma = 0.; 01853 01854 if ((i==j) && (j==k)) 01855 sigma = 1./120.; 01856 01857 else if ((i==j) || (j==k) || (i==k)) 01858 sigma = 1./360.; 01859 01860 else 01861 sigma = 1./720.; 01862 01863 v += sigma*det; 01864 vcell += sigma*det; 01865 } 01866 } 01867 } 01868 if (vmin > vcell) 01869 vmin = vcell; 01870 } 01871 } 01872 } 01873 01874 // Fill in return value references 01875 vol = v/static_cast<double>(_n_cells); 01876 Vmin = vmin; 01877 01878 return gqmin; 01879 } 01880 01881 01882 01883 // Executes one step of minimization algorithm: 01884 // finds minimization direction (P=H^{-1} \grad J) and solves approximately 01885 // local minimization problem for optimal step in this minimization direction (tau=min J(R+tau P)) 01886 double VariationalMeshSmoother::minJ(Array2D<double>& R, 01887 const std::vector<int>& mask, 01888 const Array2D<int>& cells, 01889 const std::vector<int>& mcells, 01890 double epsilon, 01891 double w, 01892 int me, 01893 const Array3D<double>& H, 01894 double vol, 01895 const std::vector<int>& edges, 01896 const std::vector<int>& hnodes, 01897 int msglev, 01898 double& Vmin, 01899 double& emax, 01900 double& qmin, 01901 int adp, 01902 const std::vector<double>& afun) 01903 { 01904 // columns - max number of nonzero entries in every row of global matrix 01905 int columns = _dim*_dim*10; 01906 01907 // local Hessian matrix 01908 Array3D<double> W(_dim, 3*_dim + _dim%2, 3*_dim + _dim%2); 01909 01910 // F - local gradient 01911 Array2D<double> F(_dim, 3*_dim + _dim%2); 01912 01913 Array2D<double> Rpr(_n_nodes, _dim); 01914 01915 // P - minimization direction 01916 Array2D<double> P(_n_nodes, _dim); 01917 01918 // A, JA - internal form of global matrix 01919 Array2D<int> JA(_dim*_n_nodes, columns); 01920 Array2D<double> A(_dim*_n_nodes, columns); 01921 01922 // G - adaptation metric 01923 Array2D<double> G(_n_cells, _dim); 01924 01925 // rhs for solver 01926 std::vector<double> b(_dim*_n_nodes); 01927 01928 // u - solution vector 01929 std::vector<double> u(_dim*_n_nodes); 01930 01931 // matrix 01932 std::vector<double> a(_dim*_n_nodes*columns); 01933 std::vector<int> ia(_dim*_n_nodes + 1); 01934 std::vector<int> ja(_dim*_n_nodes*columns); 01935 01936 // nonzero - norm of gradient 01937 double nonzero = 0.; 01938 01939 // Jpr - value of functional 01940 double Jpr = 0.; 01941 01942 // find minimization direction P 01943 for (dof_id_type i=0; i<_n_cells; i++) 01944 { 01945 int nvert = 0; 01946 while (cells[i][nvert] >= 0) 01947 nvert++; 01948 01949 // determination of local matrices on each cell 01950 for (unsigned j=0; j<_dim; j++) 01951 { 01952 G[i][j] = 0; // adaptation metric G is held constant throughout minJ run 01953 if (adp < 0) 01954 { 01955 for (int k=0; k<std::abs(adp); k++) 01956 G[i][j] += afun[i*(-adp)+k]; // cell-based adaptivity is computed here 01957 } 01958 } 01959 for (unsigned index=0; index<_dim; index++) 01960 { 01961 // initialise local matrices 01962 for (unsigned k=0; k<3*_dim + _dim%2; k++) 01963 { 01964 F[index][k] = 0; 01965 01966 for (unsigned j=0; j<3*_dim + _dim%2; j++) 01967 W[index][k][j] = 0; 01968 } 01969 } 01970 if (mcells[i] >= 0) 01971 { 01972 // if cell is not excluded 01973 double lVmin, lqmin; 01974 Jpr += localP(W, F, R, cells[i], mask, epsilon, w, nvert, H[i], 01975 me, vol, 0, lVmin, lqmin, adp, afun, G[i]); 01976 } 01977 else 01978 { 01979 for (unsigned index=0; index<_dim; index++) 01980 for (int j=0; j<nvert; j++) 01981 W[index][j][j] = 1; 01982 } 01983 01984 // assembly of an upper triangular part of a global matrix A 01985 for (unsigned index=0; index<_dim; index++) 01986 { 01987 for (int l=0; l<nvert; l++) 01988 { 01989 for (int m=0; m<nvert; m++) 01990 { 01991 if ((W[index][l][m] != 0) && 01992 (cells[i][m] >= cells[i][l])) 01993 { 01994 int sch = 0; 01995 int ind = 1; 01996 while (ind != 0) 01997 { 01998 if (A[cells[i][l] + index*_n_nodes][sch] != 0) 01999 { 02000 if (JA[cells[i][l] + index*_n_nodes][sch] == static_cast<int>(cells[i][m] + index*_n_nodes)) 02001 { 02002 A[cells[i][l] + index*_n_nodes][sch] = A[cells[i][l] + index*_n_nodes][sch] + W[index][l][m]; 02003 ind=0; 02004 } 02005 else 02006 sch++; 02007 } 02008 else 02009 { 02010 A[cells[i][l] + index*_n_nodes][sch] = W[index][l][m]; 02011 JA[cells[i][l] + index*_n_nodes][sch] = cells[i][m] + index*_n_nodes; 02012 ind = 0; 02013 } 02014 02015 if (sch > columns-1) 02016 _logfile << "error: # of nonzero entries in the " 02017 << cells[i][l] 02018 << " row of Hessian =" 02019 << sch 02020 << ">= columns=" 02021 << columns 02022 << std::endl; 02023 } 02024 } 02025 } 02026 b[cells[i][l] + index*_n_nodes] = b[cells[i][l] + index*_n_nodes] - F[index][l]; 02027 } 02028 } 02029 // end of matrix A 02030 } 02031 02032 // HN correction 02033 02034 // tolerance for HN being the mid-edge node for its parents 02035 double Tau_hn = pow(vol, 1./static_cast<double>(_dim))*1e-10; 02036 for (dof_id_type i=0; i<_n_hanging_edges; i++) 02037 { 02038 int ind_i = hnodes[i]; 02039 int ind_j = edges[2*i]; 02040 int ind_k = edges[2*i+1]; 02041 02042 for (unsigned j=0; j<_dim; j++) 02043 { 02044 int g_i = R[ind_i][j] - 0.5*(R[ind_j][j]+R[ind_k][j]); 02045 Jpr += g_i*g_i/(2*Tau_hn); 02046 b[ind_i + j*_n_nodes] -= g_i/Tau_hn; 02047 b[ind_j + j*_n_nodes] += 0.5*g_i/Tau_hn; 02048 b[ind_k + j*_n_nodes] += 0.5*g_i/Tau_hn; 02049 } 02050 02051 for (int ind=0; ind<columns; ind++) 02052 { 02053 if (JA[ind_i][ind] == ind_i) 02054 A[ind_i][ind] += 1./Tau_hn; 02055 02056 if (JA[ind_i+_n_nodes][ind] == static_cast<int>(ind_i+_n_nodes)) 02057 A[ind_i+_n_nodes][ind] += 1./Tau_hn; 02058 02059 if (_dim == 3) 02060 if (JA[ind_i+2*_n_nodes][ind] == static_cast<int>(ind_i+2*_n_nodes)) 02061 A[ind_i+2*_n_nodes][ind] += 1./Tau_hn; 02062 02063 if ((JA[ind_i][ind] == ind_j) || 02064 (JA[ind_i][ind] == ind_k)) 02065 A[ind_i][ind] -= 0.5/Tau_hn; 02066 02067 if ((JA[ind_i+_n_nodes][ind] == static_cast<int>(ind_j+_n_nodes)) || 02068 (JA[ind_i+_n_nodes][ind] == static_cast<int>(ind_k+_n_nodes))) 02069 A[ind_i+_n_nodes][ind] -= 0.5/Tau_hn; 02070 02071 if (_dim == 3) 02072 if ((JA[ind_i+2*_n_nodes][ind] == static_cast<int>(ind_j+2*_n_nodes)) || 02073 (JA[ind_i+2*_n_nodes][ind] == static_cast<int>(ind_k+2*_n_nodes))) 02074 A[ind_i+2*_n_nodes][ind] -= 0.5/Tau_hn; 02075 02076 if (JA[ind_j][ind] == ind_i) 02077 A[ind_j][ind] -= 0.5/Tau_hn; 02078 02079 if (JA[ind_k][ind] == ind_i) 02080 A[ind_k][ind] -= 0.5/Tau_hn; 02081 02082 if (JA[ind_j+_n_nodes][ind] == static_cast<int>(ind_i+_n_nodes)) 02083 A[ind_j+_n_nodes][ind] -= 0.5/Tau_hn; 02084 02085 if (JA[ind_k+_n_nodes][ind] == static_cast<int>(ind_i+_n_nodes)) 02086 A[ind_k+_n_nodes][ind] -= 0.5/Tau_hn; 02087 02088 if (_dim == 3) 02089 if (JA[ind_j+2*_n_nodes][ind] == static_cast<int>(ind_i+2*_n_nodes)) 02090 A[ind_j+2*_n_nodes][ind] -= 0.5/Tau_hn; 02091 02092 if (_dim == 3) 02093 if (JA[ind_k+2*_n_nodes][ind] == static_cast<int>(ind_i+2*_n_nodes)) 02094 A[ind_k+2*_n_nodes][ind] -= 0.5/Tau_hn; 02095 02096 if ((JA[ind_j][ind] == ind_j) || 02097 (JA[ind_j][ind] == ind_k)) 02098 A[ind_j][ind] += 0.25/Tau_hn; 02099 02100 if ((JA[ind_k][ind] == ind_j) || 02101 (JA[ind_k][ind] == ind_k)) 02102 A[ind_k][ind] += 0.25/Tau_hn; 02103 02104 if ((JA[ind_j+_n_nodes][ind] == static_cast<int>(ind_j+_n_nodes)) || 02105 (JA[ind_j+_n_nodes][ind] == static_cast<int>(ind_k+_n_nodes))) 02106 A[ind_j+_n_nodes][ind] += 0.25/Tau_hn; 02107 02108 if ((JA[ind_k+_n_nodes][ind] == static_cast<int>(ind_j+_n_nodes)) || 02109 (JA[ind_k+_n_nodes][ind] == static_cast<int>(ind_k+_n_nodes))) 02110 A[ind_k+_n_nodes][ind] += 0.25/Tau_hn; 02111 02112 if (_dim == 3) 02113 if ((JA[ind_j+2*_n_nodes][ind] == static_cast<int>(ind_j+2*_n_nodes)) || 02114 (JA[ind_j+2*_n_nodes][ind] == static_cast<int>(ind_k+2*_n_nodes))) 02115 A[ind_j+2*_n_nodes][ind] += 0.25/Tau_hn; 02116 02117 if (_dim==3) 02118 if ((JA[ind_k+2*_n_nodes][ind] == static_cast<int>(ind_j+2*_n_nodes)) || 02119 (JA[ind_k+2*_n_nodes][ind] == static_cast<int>(ind_k+2*_n_nodes))) 02120 A[ind_k+2*_n_nodes][ind] += 0.25/Tau_hn; 02121 } 02122 } 02123 02124 // ||\grad J||_2 02125 for (dof_id_type i=0; i<_dim*_n_nodes; i++) 02126 nonzero += b[i]*b[i]; 02127 02128 // sort matrix A 02129 for (dof_id_type i=0; i<_dim*_n_nodes; i++) 02130 { 02131 for (int j=columns-1; j>1; j--) 02132 { 02133 for (int k=0; k<j; k++) 02134 { 02135 if (JA[i][k] > JA[i][k+1]) 02136 { 02137 int sch = JA[i][k]; 02138 JA[i][k] = JA[i][k+1]; 02139 JA[i][k+1] = sch; 02140 double tmp = A[i][k]; 02141 A[i][k] = A[i][k+1]; 02142 A[i][k+1] = tmp; 02143 } 02144 } 02145 } 02146 } 02147 02148 double eps = std::sqrt(vol)*1e-9; 02149 02150 // solver for P (unconstrained) 02151 ia[0] = 0; 02152 { 02153 int j = 0; 02154 for (dof_id_type i=0; i<_dim*_n_nodes; i++) 02155 { 02156 u[i] = 0; 02157 int nz = 0; 02158 for (int k=0; k<columns; k++) 02159 { 02160 if (A[i][k] != 0) 02161 { 02162 nz++; 02163 ja[j] = JA[i][k]+1; 02164 a[j] = A[i][k]; 02165 j++; 02166 } 02167 } 02168 ia[i+1] = ia[i] + nz; 02169 } 02170 } 02171 02172 dof_id_type m = _dim*_n_nodes; 02173 int sch = (msglev >= 3) ? 1 : 0; 02174 02175 solver(m, ia, ja, a, u, b, eps, 100, sch); 02176 // sol_pcg_pj(m, ia, ja, a, u, b, eps, 100, sch); 02177 02178 for (dof_id_type i=0; i<_n_nodes; i++) 02179 { 02180 //ensure fixed nodes are not moved 02181 for (unsigned index=0; index<_dim; index++) 02182 if (mask[i] == 1) 02183 P[i][index] = 0; 02184 else 02185 P[i][index] = u[i+index*_n_nodes]; 02186 } 02187 02188 // P is determined 02189 if (msglev >= 4) 02190 { 02191 for (dof_id_type i=0; i<_n_nodes; i++) 02192 { 02193 for (unsigned j=0; j<_dim; j++) 02194 if (P[i][j] != 0) 02195 _logfile << "P[" << i << "][" << j << "]=" << P[i][j]; 02196 } 02197 } 02198 02199 // local minimization problem, determination of tau 02200 if (msglev >= 3) 02201 _logfile << "dJ=" << std::sqrt(nonzero) << " J0=" << Jpr << std::endl; 02202 02203 double 02204 J = 1.e32, 02205 tau = 0., 02206 gVmin = 0., 02207 gemax = 0., 02208 gqmin = 0.; 02209 02210 int j = 1; 02211 02212 while ((Jpr <= J) && (j > -30)) 02213 { 02214 j = j-1; 02215 02216 // search through finite # of values for tau 02217 tau = pow(2., j); 02218 for (dof_id_type i=0; i<_n_nodes; i++) 02219 for (unsigned k=0; k<_dim; k++) 02220 Rpr[i][k] = R[i][k] + tau*P[i][k]; 02221 02222 J = 0; 02223 gVmin = 1e32; 02224 gemax = -1e32; 02225 gqmin = 1e32; 02226 for (dof_id_type i=0; i<_n_cells; i++) 02227 { 02228 if (mcells[i] >= 0) 02229 { 02230 int nvert = 0; 02231 while (cells[i][nvert] >= 0) 02232 nvert++; 02233 02234 double lVmin, lqmin; 02235 double lemax = localP(W, F, Rpr, cells[i], mask, epsilon, w, nvert, H[i], me, vol, 1, lVmin, lqmin, adp, afun, G[i]); 02236 02237 J += lemax; 02238 if (gVmin > lVmin) 02239 gVmin = lVmin; 02240 02241 if (gemax < lemax) 02242 gemax = lemax; 02243 02244 if (gqmin > lqmin) 02245 gqmin = lqmin; 02246 02247 // HN correction 02248 for (dof_id_type ii=0; ii<_n_hanging_edges; ii++) 02249 { 02250 int ind_i = hnodes[ii]; 02251 int ind_j = edges[2*ii]; 02252 int ind_k = edges[2*ii+1]; 02253 for (unsigned jj=0; jj<_dim; jj++) 02254 { 02255 int g_i = Rpr[ind_i][jj] - 0.5*(Rpr[ind_j][jj]+Rpr[ind_k][jj]); 02256 J += g_i*g_i/(2*Tau_hn); 02257 } 02258 } 02259 } 02260 } 02261 if (msglev >= 3) 02262 _logfile << "tau=" << tau << " J=" << J << std::endl; 02263 } 02264 02265 02266 double 02267 T = 0., 02268 gtmin0 = 0., 02269 gtmax0 = 0., 02270 gqmin0 = 0.; 02271 02272 if (j != -30) 02273 { 02274 Jpr = J; 02275 for (unsigned i=0; i<_n_nodes; i++) 02276 for (unsigned k=0; k<_dim; k++) 02277 Rpr[i][k] = R[i][k] + tau*0.5*P[i][k]; 02278 02279 J = 0; 02280 gtmin0 = 1e32; 02281 gtmax0 = -1e32; 02282 gqmin0 = 1e32; 02283 for (dof_id_type i=0; i<_n_cells; i++) 02284 { 02285 if (mcells[i] >= 0) 02286 { 02287 int nvert = 0; 02288 while (cells[i][nvert] >= 0) 02289 nvert++; 02290 02291 double lVmin, lqmin; 02292 double lemax = localP(W, F, Rpr, cells[i], mask, epsilon, w, nvert, H[i], me, vol, 1, lVmin, lqmin, adp, afun, G[i]); 02293 J += lemax; 02294 02295 if (gtmin0 > lVmin) 02296 gtmin0 = lVmin; 02297 02298 if (gtmax0 < lemax) 02299 gtmax0 = lemax; 02300 02301 if (gqmin0 > lqmin) 02302 gqmin0 = lqmin; 02303 02304 // HN correction 02305 for (dof_id_type ii=0; ii<_n_hanging_edges; ii++) 02306 { 02307 int ind_i = hnodes[ii]; 02308 int ind_j = edges[2*ii]; 02309 int ind_k = edges[2*ii+1]; 02310 02311 for (unsigned jj=0; jj<_dim; jj++) 02312 { 02313 int g_i = Rpr[ind_i][jj] - 0.5*(Rpr[ind_j][jj] + Rpr[ind_k][jj]); 02314 J += g_i*g_i/(2*Tau_hn); 02315 } 02316 } 02317 } 02318 } 02319 } 02320 02321 if (Jpr > J) 02322 { 02323 T = 0.5*tau; 02324 // Set up return values passed by reference 02325 Vmin = gtmin0; 02326 emax = gtmax0; 02327 qmin = gqmin0; 02328 } 02329 else 02330 { 02331 T = tau; 02332 J = Jpr; 02333 // Set up return values passed by reference 02334 Vmin = gVmin; 02335 emax = gemax; 02336 qmin = gqmin; 02337 } 02338 02339 nonzero = 0; 02340 for (dof_id_type j=0; j<_n_nodes; j++) 02341 for (unsigned k=0; k<_dim; k++) 02342 { 02343 R[j][k] = R[j][k] + T*P[j][k]; 02344 nonzero += T*P[j][k]*T*P[j][k]; 02345 } 02346 02347 if (msglev >= 2) 02348 _logfile << "tau=" << T << ", J=" << J << std::endl; 02349 02350 return std::sqrt(nonzero); 02351 } 02352 02353 02354 02355 // minJ() with sliding Boundary Nodes constraints and no account for HN, 02356 // using Lagrange multiplier formulation: minimize L=J+\sum lam*g; 02357 // only works in 2D 02358 double VariationalMeshSmoother::minJ_BC(Array2D<double>& R, 02359 const std::vector<int>& mask, 02360 const Array2D<int>& cells, 02361 const std::vector<int>& mcells, 02362 double epsilon, 02363 double w, 02364 int me, 02365 const Array3D<double>& H, 02366 double vol, 02367 int msglev, 02368 double& Vmin, 02369 double& emax, 02370 double& qmin, 02371 int adp, 02372 const std::vector<double>& afun, 02373 int NCN) 02374 { 02375 // new form of matrices, 5 iterations for minL 02376 double tau = 0., J = 0., T, Jpr, L, lVmin, lqmin, gVmin = 0., gqmin = 0., gVmin0 = 0., 02377 gqmin0 = 0., lemax, gemax = 0., gemax0 = 0.; 02378 02379 // array of sliding BN 02380 std::vector<int> Bind(NCN); 02381 std::vector<double> lam(NCN); 02382 std::vector<double> hm(2*_n_nodes); 02383 std::vector<double> Plam(NCN); 02384 02385 // holds constraints = local approximation to the boundary 02386 std::vector<double> constr(4*NCN); 02387 02388 Array2D<double> F(2, 6); 02389 Array3D<double> W(2, 6, 6); 02390 Array2D<double> Rpr(_n_nodes, 2); 02391 Array2D<double> P(_n_nodes, 2); 02392 02393 std::vector<double> b(2*_n_nodes); 02394 02395 Array2D<double> G(_n_cells, 6); 02396 02397 // assembler of constraints 02398 const double eps = std::sqrt(vol)*1e-9; 02399 02400 for (int i=0; i<4*NCN; i++) 02401 constr[i] = 1./eps; 02402 02403 { 02404 int I = 0; 02405 for (dof_id_type i=0; i<_n_nodes; i++) 02406 if (mask[i] == 2) 02407 { 02408 Bind[I] = i; 02409 I++; 02410 } 02411 } 02412 02413 for (int I=0; I<NCN; I++) 02414 { 02415 // The boundary connectivity loop sets up the j and k indices 02416 // but I am not sure about the logic of this: j and k are overwritten 02417 // at every iteration of the boundary connectivity loop and only used 02418 // *after* the boundary connectivity loop -- this seems like a bug but 02419 // I maintained the original behavior of the algorithm [JWP]. 02420 int 02421 i = Bind[I], 02422 j = 0, 02423 k = 0, 02424 ind = 0; 02425 02426 // boundary connectivity 02427 for (dof_id_type l=0; l<_n_cells; l++) 02428 { 02429 int nvert = 0; 02430 02431 while (cells[l][nvert] >= 0) 02432 nvert++; 02433 02434 switch (nvert) 02435 { 02436 case 3: // tri 02437 if (i == cells[l][0]) 02438 { 02439 if (mask[cells[l][1]] > 0) 02440 { 02441 if (ind == 0) 02442 j = cells[l][1]; 02443 else 02444 k = cells[l][1]; 02445 ind++; 02446 } 02447 02448 if (mask[cells[l][2]] > 0) 02449 { 02450 if (ind == 0) 02451 j = cells[l][2]; 02452 else 02453 k = cells[l][2]; 02454 ind++; 02455 } 02456 } 02457 02458 if (i == cells[l][1]) 02459 { 02460 if (mask[cells[l][0]] > 0) 02461 { 02462 if (ind == 0) 02463 j = cells[l][0]; 02464 else 02465 k = cells[l][0]; 02466 ind++; 02467 } 02468 02469 if (mask[cells[l][2]] > 0) 02470 { 02471 if (ind == 0) 02472 j = cells[l][2]; 02473 else 02474 k = cells[l][2]; 02475 ind++; 02476 } 02477 } 02478 02479 if (i == cells[l][2]) 02480 { 02481 if (mask[cells[l][1]] > 0) 02482 { 02483 if (ind == 0) 02484 j = cells[l][1]; 02485 else 02486 k = cells[l][1]; 02487 ind++; 02488 } 02489 02490 if (mask[cells[l][0]] > 0) 02491 { 02492 if (ind == 0) 02493 j = cells[l][0]; 02494 else 02495 k = cells[l][0]; 02496 ind++; 02497 } 02498 } 02499 break; 02500 02501 case 4: // quad 02502 if ((i == cells[l][0]) || 02503 (i == cells[l][3])) 02504 { 02505 if (mask[cells[l][1]] > 0) 02506 { 02507 if (ind == 0) 02508 j = cells[l][1]; 02509 else 02510 k = cells[l][1]; 02511 ind++; 02512 } 02513 02514 if (mask[cells[l][2]] > 0) 02515 { 02516 if (ind == 0) 02517 j = cells[l][2]; 02518 else 02519 k = cells[l][2]; 02520 ind++; 02521 } 02522 } 02523 02524 if ((i == cells[l][1]) || 02525 (i == cells[l][2])) 02526 { 02527 if (mask[cells[l][0]] > 0) 02528 { 02529 if (ind == 0) 02530 j = cells[l][0]; 02531 else 02532 k = cells[l][0]; 02533 ind++; 02534 } 02535 02536 if (mask[cells[l][3]] > 0) 02537 { 02538 if (ind == 0) 02539 j = cells[l][3]; 02540 else 02541 k = cells[l][3]; 02542 ind++; 02543 } 02544 } 02545 break; 02546 02547 case 6: //quad tri 02548 if (i == cells[l][0]) 02549 { 02550 if (mask[cells[l][1]] > 0) 02551 { 02552 if (ind == 0) 02553 j = cells[l][5]; 02554 else 02555 k = cells[l][5]; 02556 ind++; 02557 } 02558 02559 if (mask[cells[l][2]] > 0) 02560 { 02561 if (ind == 0) 02562 j = cells[l][4]; 02563 else 02564 k = cells[l][4]; 02565 ind++; 02566 } 02567 } 02568 02569 if (i == cells[l][1]) 02570 { 02571 if (mask[cells[l][0]] > 0) 02572 { 02573 if (ind == 0) 02574 j = cells[l][5]; 02575 else 02576 k = cells[l][5]; 02577 ind++; 02578 } 02579 02580 if (mask[cells[l][2]] > 0) 02581 { 02582 if (ind == 0) 02583 j = cells[l][3]; 02584 else 02585 k = cells[l][3]; 02586 ind++; 02587 } 02588 } 02589 02590 if (i == cells[l][2]) 02591 { 02592 if (mask[cells[l][1]] > 0) 02593 { 02594 if (ind == 0) 02595 j = cells[l][3]; 02596 else 02597 k = cells[l][3]; 02598 ind++; 02599 } 02600 02601 if (mask[cells[l][0]] > 0) 02602 { 02603 if (ind == 0) 02604 j = cells[l][4]; 02605 else 02606 k = cells[l][4]; 02607 ind++; 02608 } 02609 } 02610 02611 if (i == cells[l][3]) 02612 { 02613 j = cells[l][1]; 02614 k = cells[l][2]; 02615 } 02616 02617 if (i == cells[l][4]) 02618 { 02619 j = cells[l][2]; 02620 k = cells[l][0]; 02621 } 02622 02623 if (i == cells[l][5]) 02624 { 02625 j = cells[l][0]; 02626 k = cells[l][1]; 02627 } 02628 break; 02629 02630 default: 02631 libmesh_error_msg("Unrecognized nvert = " << nvert); 02632 } 02633 } // end boundary connectivity 02634 02635 // lines 02636 double del1 = R[j][0] - R[i][0]; 02637 double del2 = R[i][0] - R[k][0]; 02638 02639 if ((std::abs(del1) < eps) && 02640 (std::abs(del2) < eps)) 02641 { 02642 constr[I*4] = 1; 02643 constr[I*4+1] = 0; 02644 constr[I*4+2] = R[i][0]; 02645 constr[I*4+3] = R[i][1]; 02646 } 02647 else 02648 { 02649 del1 = R[j][1] - R[i][1]; 02650 del2 = R[i][1] - R[k][1]; 02651 if ((std::abs(del1) < eps) && 02652 (std::abs(del2) < eps)) 02653 { 02654 constr[I*4] = 0; 02655 constr[I*4+1] = 1; 02656 constr[I*4+2] = R[i][0]; 02657 constr[I*4+3] = R[i][1]; 02658 } 02659 else 02660 { 02661 J = 02662 (R[i][0]-R[j][0])*(R[k][1]-R[j][1]) - 02663 (R[k][0]-R[j][0])*(R[i][1]-R[j][1]); 02664 02665 if (std::abs(J) < eps) 02666 { 02667 constr[I*4] = 1./(R[k][0]-R[j][0]); 02668 constr[I*4+1] = -1./(R[k][1]-R[j][1]); 02669 constr[I*4+2] = R[i][0]; 02670 constr[I*4+3] = R[i][1]; 02671 } 02672 else 02673 { 02674 // circle 02675 double x0 = ((R[k][1]-R[j][1])*(R[i][0]*R[i][0]-R[j][0]*R[j][0]+R[i][1]*R[i][1]-R[j][1]*R[j][1]) + 02676 (R[j][1]-R[i][1])*(R[k][0]*R[k][0]-R[j][0]*R[j][0]+R[k][1]*R[k][1]-R[j][1]*R[j][1]))/(2*J); 02677 double y0 = ((R[j][0]-R[k][0])*(R[i][0]*R[i][0]-R[j][0]*R[j][0]+R[i][1]*R[i][1]-R[j][1]*R[j][1]) + 02678 (R[i][0]-R[j][0])*(R[k][0]*R[k][0]-R[j][0]*R[j][0]+R[k][1]*R[k][1]-R[j][1]*R[j][1]))/(2*J); 02679 constr[I*4] = x0; 02680 constr[I*4+1] = y0; 02681 constr[I*4+2] = (R[i][0]-x0)*(R[i][0]-x0) + (R[i][1]-y0)*(R[i][1]-y0); 02682 } 02683 } 02684 } 02685 } 02686 02687 // for (int i=0; i<NCN; i++){ 02688 // for (int j=0; j<4; j++) fprintf(stdout," %e ",constr[4*i+j]); 02689 // fprintf(stdout, "constr %d node %d \n",i,Bind[i]); 02690 // } 02691 02692 // initial values 02693 for (int i=0; i<NCN; i++) 02694 lam[i] = 0; 02695 02696 // Eventual return value 02697 double nonzero = 0.; 02698 02699 // Temporary result variable 02700 double qq = 0.; 02701 02702 for (int nz=0; nz<5; nz++) 02703 { 02704 // find H and -grad J 02705 nonzero = 0.; 02706 Jpr = 0; 02707 for (dof_id_type i=0; i<2*_n_nodes; i++) 02708 { 02709 b[i] = 0; 02710 hm[i] = 0; 02711 } 02712 02713 for (dof_id_type i=0; i<_n_cells; i++) 02714 { 02715 int nvert = 0; 02716 02717 while (cells[i][nvert] >= 0) 02718 nvert++; 02719 02720 for (int j=0; j<nvert; j++) 02721 { 02722 G[i][j] = 0; 02723 if (adp < 0) 02724 for (int k=0; k<std::abs(adp); k++) 02725 G[i][j] += afun[i*(-adp) + k]; 02726 } 02727 02728 for (int index=0; index<2; index++) 02729 for (int k=0; k<nvert; k++) 02730 { 02731 F[index][k] = 0; 02732 for (int j=0; j<nvert; j++) 02733 W[index][k][j] = 0; 02734 } 02735 02736 if (mcells[i] >= 0) 02737 Jpr += localP(W, F, R, cells[i], mask, epsilon, w, nvert, H[i], 02738 me, vol, 0, lVmin, lqmin, adp, afun, G[i]); 02739 02740 else 02741 { 02742 for (unsigned index=0; index<2; index++) 02743 for (int j=0; j<nvert; j++) 02744 W[index][j][j] = 1; 02745 } 02746 02747 for (unsigned index=0; index<2; index++) 02748 for (int l=0; l<nvert; l++) 02749 { 02750 // diagonal Hessian 02751 hm[cells[i][l] + index*_n_nodes] += W[index][l][l]; 02752 b[cells[i][l] + index*_n_nodes] -= F[index][l]; 02753 } 02754 } 02755 02756 // ||grad J||_2 02757 for (dof_id_type i=0; i<2*_n_nodes; i++) 02758 nonzero += b[i]*b[i]; 02759 02760 // solve for Plam 02761 for (int I=0; I<NCN; I++) 02762 { 02763 int i = Bind[I]; 02764 double 02765 Bx = 0., 02766 By = 0., 02767 g = 0.; 02768 02769 if (constr[4*I+3] < 0.5/eps) 02770 { 02771 Bx = constr[4*I]; 02772 By = constr[4*I+1]; 02773 g = (R[i][0]-constr[4*I+2])*constr[4*I] + (R[i][1]-constr[4*I+3])*constr[4*I+1]; 02774 } 02775 else 02776 { 02777 Bx = 2*(R[i][0] - constr[4*I]); 02778 By = 2*(R[i][1] - constr[4*I+1]); 02779 hm[i] += 2*lam[I]; 02780 hm[i+_n_nodes] += 2*lam[I]; 02781 g = 02782 (R[i][0] - constr[4*I])*(R[i][0]-constr[4*I]) + 02783 (R[i][1] - constr[4*I+1])*(R[i][1]-constr[4*I+1]) - constr[4*I+2]; 02784 } 02785 02786 Jpr += lam[I]*g; 02787 qq = Bx*b[i]/hm[i] + By*b[i+_n_nodes]/hm[i+_n_nodes] - g; 02788 double a = Bx*Bx/hm[i] + By*By/hm[i+_n_nodes]; 02789 02790 if (a != 0) 02791 Plam[I] = qq/a; 02792 else 02793 _logfile << "error: B^TH-1B is degenerate" << std::endl; 02794 02795 b[i] -= Plam[I]*Bx; 02796 b[i+_n_nodes] -= Plam[I]*By; 02797 Plam[I] -= lam[I]; 02798 } 02799 02800 // solve for P 02801 for (dof_id_type i=0; i<_n_nodes; i++) 02802 { 02803 P[i][0] = b[i]/hm[i]; 02804 P[i][1] = b[i+_n_nodes]/hm[i+_n_nodes]; 02805 } 02806 02807 // correct solution 02808 for (dof_id_type i=0; i<_n_nodes; i++) 02809 for (unsigned j=0; j<2; j++) 02810 if ((std::abs(P[i][j]) < eps) || (mask[i] == 1)) 02811 P[i][j] = 0; 02812 02813 // P is determined 02814 if (msglev >= 3) 02815 { 02816 for (dof_id_type i=0; i<_n_nodes; i++) 02817 for (unsigned j=0; j<2; j++) 02818 if (P[i][j] != 0) 02819 _logfile << "P[" << i << "][" << j << "]=" << P[i][j] << " "; 02820 } 02821 02822 // local minimization problem, determination of tau 02823 if (msglev >= 3) 02824 _logfile << "dJ=" << std::sqrt(nonzero) << " L0=" << Jpr << std::endl; 02825 02826 L = 1.e32; 02827 int j = 1; 02828 02829 while ((Jpr <= L) && (j > -30)) 02830 { 02831 j = j-1; 02832 tau = pow(2.,j); 02833 for (dof_id_type i=0; i<_n_nodes; i++) 02834 for (unsigned k=0; k<2; k++) 02835 Rpr[i][k] = R[i][k] + tau*P[i][k]; 02836 02837 J = 0; 02838 gVmin = 1.e32; 02839 gemax = -1.e32; 02840 gqmin = 1.e32; 02841 for (dof_id_type i=0; i<_n_cells; i++) 02842 if (mcells[i] >= 0) 02843 { 02844 int nvert = 0; 02845 while (cells[i][nvert] >= 0) 02846 nvert++; 02847 02848 lemax = localP(W, F, Rpr, cells[i], mask, epsilon, w, nvert, H[i], me, vol, 1, lVmin, 02849 lqmin, adp, afun, G[i]); 02850 J += lemax; 02851 02852 if (gVmin > lVmin) 02853 gVmin = lVmin; 02854 02855 if (gemax < lemax) 02856 gemax = lemax; 02857 02858 if (gqmin > lqmin) 02859 gqmin = lqmin; 02860 } 02861 02862 L = J; 02863 02864 // constraints contribution 02865 for (int I=0; I<NCN; I++) 02866 { 02867 int i = Bind[I]; 02868 double g = 0.; 02869 02870 if (constr[4*I+3] < 0.5/eps) 02871 g = (Rpr[i][0] - constr[4*I+2])*constr[4*I] + (Rpr[i][1]-constr[4*I+3])*constr[4*I+1]; 02872 02873 else 02874 g = (Rpr[i][0]-constr[4*I])*(Rpr[i][0]-constr[4*I]) + 02875 (Rpr[i][1]-constr[4*I+1])*(Rpr[i][1]-constr[4*I+1]) - constr[4*I+2]; 02876 02877 L += (lam[I] + tau*Plam[I])*g; 02878 } 02879 02880 // end of constraints 02881 if (msglev >= 3) 02882 _logfile << " tau=" << tau << " J=" << J << std::endl; 02883 } // end while 02884 02885 if (j == -30) 02886 T = 0; 02887 else 02888 { 02889 Jpr = L; 02890 qq = J; 02891 for (dof_id_type i=0; i<_n_nodes; i++) 02892 for (unsigned k=0; k<2; k++) 02893 Rpr[i][k] = R[i][k] + tau*0.5*P[i][k]; 02894 02895 J = 0; 02896 gVmin0 = 1.e32; 02897 gemax0 = -1.e32; 02898 gqmin0 = 1.e32; 02899 02900 for (dof_id_type i=0; i<_n_cells; i++) 02901 if (mcells[i] >= 0) 02902 { 02903 int nvert = 0; 02904 while (cells[i][nvert] >= 0) 02905 nvert++; 02906 02907 lemax = localP(W, F, Rpr, cells[i], mask, epsilon, w, nvert, H[i], me, vol, 1, lVmin, 02908 lqmin, adp, afun, G[i]); 02909 J += lemax; 02910 02911 if (gVmin0 > lVmin) 02912 gVmin0 = lVmin; 02913 02914 if (gemax0 < lemax) 02915 gemax0 = lemax; 02916 02917 if (gqmin0 > lqmin) 02918 gqmin0 = lqmin; 02919 } 02920 02921 L = J; 02922 02923 // constraints contribution 02924 for (int I=0; I<NCN; I++) 02925 { 02926 int i = Bind[I]; 02927 double g = 0.; 02928 02929 if (constr[4*I+3] < 0.5/eps) 02930 g = (Rpr[i][0]-constr[4*I+2])*constr[4*I] + (Rpr[i][1]-constr[4*I+3])*constr[4*I+1]; 02931 02932 else 02933 g = (Rpr[i][0]-constr[4*I])*(Rpr[i][0]-constr[4*I]) + 02934 (Rpr[i][1]-constr[4*I+1])*(Rpr[i][1]-constr[4*I+1]) - constr[4*I+2]; 02935 02936 L += (lam[I] + tau*0.5*Plam[I])*g; 02937 } 02938 // end of constraints 02939 } 02940 02941 if (Jpr > L) 02942 { 02943 T = 0.5*tau; 02944 // Set return values by reference 02945 Vmin = gVmin0; 02946 emax = gemax0; 02947 qmin = gqmin0; 02948 } 02949 else 02950 { 02951 T = tau; 02952 L = Jpr; 02953 J = qq; 02954 // Set return values by reference 02955 Vmin = gVmin; 02956 emax = gemax; 02957 qmin = gqmin; 02958 } 02959 02960 for (dof_id_type i=0; i<_n_nodes; i++) 02961 for (unsigned k=0; k<2; k++) 02962 R[i][k] += T*P[i][k]; 02963 02964 for (int i=0; i<NCN; i++) 02965 lam[i] += T*Plam[i]; 02966 02967 } // end Lagrangian iter 02968 02969 if (msglev >= 2) 02970 _logfile << "tau=" << T << ", J=" << J << ", L=" << L << std::endl; 02971 02972 return std::sqrt(nonzero); 02973 } 02974 02975 02976 02977 // composes local matrix W and right side F from all quadrature nodes of one cell 02978 double VariationalMeshSmoother::localP(Array3D<double>& W, 02979 Array2D<double>& F, 02980 Array2D<double>& R, 02981 const std::vector<int>& cell_in, 02982 const std::vector<int>& mask, 02983 double epsilon, 02984 double w, 02985 int nvert, 02986 const Array2D<double>& H, 02987 int me, 02988 double vol, 02989 int f, 02990 double& Vmin, 02991 double& qmin, 02992 int adp, 02993 const std::vector<double>& afun, 02994 std::vector<double>& Gloc) 02995 { 02996 // K - determines approximation rule for local integral over the cell 02997 std::vector<double> K(9); 02998 02999 // f - flag, f=0 for determination of Hessian and gradient of the functional, 03000 // f=1 for determination of the functional value only; 03001 // adaptivity is determined on the first step for adp>0 (nodal based) 03002 if (f == 0) 03003 { 03004 if (adp > 0) 03005 avertex(afun, Gloc, R, cell_in, nvert, adp); 03006 if (adp == 0) 03007 { 03008 for (unsigned i=0; i<_dim; i++) 03009 Gloc[i] = 1.; 03010 } 03011 } 03012 03013 double 03014 sigma = 0., 03015 fun = 0, 03016 gqmin = 1e32, 03017 g = 0, // Vmin 03018 lqmin = 0.; 03019 03020 // cell integration depending on cell type 03021 if (_dim == 2) 03022 { 03023 // 2D 03024 if (nvert == 3) 03025 { 03026 // tri 03027 sigma = 1.; 03028 fun += vertex(W, F, R, cell_in, epsilon, w, nvert, K, H, me, vol, f, lqmin, adp, Gloc, sigma); 03029 g += sigma*lqmin; 03030 if (gqmin > lqmin) 03031 gqmin = lqmin; 03032 } 03033 if (nvert == 4) 03034 { 03035 //quad 03036 for (unsigned i=0; i<2; i++) 03037 { 03038 K[0] = i; 03039 for (unsigned j=0; j<2; j++) 03040 { 03041 K[1] = j; 03042 sigma = 0.25; 03043 fun += vertex(W, F, R, cell_in, epsilon, w, nvert, K, H, me, 03044 vol, f, lqmin, adp, Gloc, sigma); 03045 g += sigma*lqmin; 03046 if (gqmin > lqmin) 03047 gqmin = lqmin; 03048 } 03049 } 03050 } 03051 else 03052 { 03053 // quad tri 03054 for (unsigned i=0; i<3; i++) 03055 { 03056 K[0] = i*0.5; 03057 unsigned k = i/2; 03058 K[1] = static_cast<double>(k); 03059 03060 for (unsigned j=0; j<3; j++) 03061 { 03062 K[2] = j*0.5; 03063 k = j/2; 03064 K[3] = static_cast<double>(k); 03065 if (i == j) 03066 sigma = 1./12.; 03067 else 03068 sigma = 1./24.; 03069 03070 fun += vertex(W, F, R, cell_in, epsilon, w, nvert, K, H, me, 03071 vol, f, lqmin, adp, Gloc, sigma); 03072 g += sigma*lqmin; 03073 if (gqmin > lqmin) 03074 gqmin = lqmin; 03075 } 03076 } 03077 } 03078 } 03079 if (_dim == 3) 03080 { 03081 // 3D 03082 if (nvert == 4) 03083 { 03084 // tetr 03085 sigma = 1.; 03086 fun += vertex(W, F, R, cell_in, epsilon, w, nvert, K, H, me, 03087 vol, f, lqmin, adp, Gloc, sigma); 03088 g += sigma*lqmin; 03089 if (gqmin > lqmin) 03090 gqmin = lqmin; 03091 } 03092 if (nvert == 6) 03093 { 03094 //prism 03095 for (unsigned i=0; i<2; i++) 03096 { 03097 K[0] = i; 03098 for (unsigned j=0; j<2; j++) 03099 { 03100 K[1] = j; 03101 for (unsigned k=0; k<3; k++) 03102 { 03103 K[2] = 0.5*static_cast<double>(k); 03104 K[3] = static_cast<double>(k % 2); 03105 sigma = 1./12.; 03106 fun += vertex(W, F, R, cell_in, epsilon, w, nvert, K, H, me, 03107 vol, f, lqmin, adp, Gloc, sigma); 03108 g += sigma*lqmin; 03109 if (gqmin > lqmin) 03110 gqmin = lqmin; 03111 } 03112 } 03113 } 03114 } 03115 if (nvert == 8) 03116 { 03117 // hex 03118 for (unsigned i=0; i<2; i++) 03119 { 03120 K[0] = i; 03121 for (unsigned j=0; j<2; j++) 03122 { 03123 K[1] = j; 03124 for (unsigned k=0; k<2; k++) 03125 { 03126 K[2] = k; 03127 for (unsigned l=0; l<2; l++) 03128 { 03129 K[3] = l; 03130 for (unsigned m=0; m<2; m++) 03131 { 03132 K[4] = m; 03133 for (unsigned nn=0; nn<2; nn++) 03134 { 03135 K[5] = nn; 03136 03137 if ((i==nn) && (j==l) && (k==m)) 03138 sigma = 1./27.; 03139 03140 if (((i==nn) && (j==l) && (k!=m)) || 03141 ((i==nn) && (j!=l) && (k==m)) || 03142 ((i!=nn) && (j==l) && (k==m))) 03143 sigma = 1./54.; 03144 03145 if (((i==nn) && (j!=l) && (k!=m)) || 03146 ((i!=nn) && (j!=l) && (k==m)) || 03147 ((i!=nn) && (j==l) && (k!=m))) 03148 sigma = 1./108.; 03149 03150 if ((i!=nn) && (j!=l) && (k!=m)) 03151 sigma=1./216.; 03152 03153 fun += vertex(W, F, R, cell_in, epsilon, w, nvert, K, H, me, 03154 vol, f, lqmin, adp, Gloc, sigma); 03155 g += sigma*lqmin; 03156 03157 if (gqmin > lqmin) 03158 gqmin = lqmin; 03159 } 03160 } 03161 } 03162 } 03163 } 03164 } 03165 } 03166 else 03167 { 03168 // quad tetr 03169 for (unsigned i=0; i<4; i++) 03170 { 03171 for (unsigned j=0; j<4; j++) 03172 { 03173 for (unsigned k=0; k<4; k++) 03174 { 03175 switch (i) 03176 { 03177 case 0: 03178 K[0] = 0; 03179 K[1] = 0; 03180 K[2] = 0; 03181 break; 03182 03183 case 1: 03184 K[0] = 1; 03185 K[1] = 0; 03186 K[2] = 0; 03187 break; 03188 03189 case 2: 03190 K[0] = 0.5; 03191 K[1] = 1; 03192 K[2] = 0; 03193 break; 03194 03195 case 3: 03196 K[0] = 0.5; 03197 K[1] = 1./3.; 03198 K[2] = 1; 03199 break; 03200 } 03201 03202 switch (j) 03203 { 03204 case 0: 03205 K[3] = 0; 03206 K[4] = 0; 03207 K[5] = 0; 03208 break; 03209 03210 case 1: 03211 K[3] = 1; 03212 K[4] = 0; 03213 K[5] = 0; 03214 break; 03215 03216 case 2: 03217 K[3] = 0.5; 03218 K[4] = 1; 03219 K[5] = 0; 03220 break; 03221 03222 case 3: 03223 K[3] = 0.5; 03224 K[4] = 1./3.; 03225 K[5] = 1; 03226 break; 03227 03228 } 03229 03230 switch (k) 03231 { 03232 case 0: 03233 K[6] = 0; 03234 K[7] = 0; 03235 K[8] = 0; 03236 break; 03237 03238 case 1: 03239 K[6] = 1; 03240 K[7] = 0; 03241 K[8] = 0; 03242 break; 03243 03244 case 2: 03245 K[6] = 0.5; 03246 K[7] = 1; 03247 K[8] = 0; 03248 break; 03249 03250 case 3: 03251 K[6] = 0.5; 03252 K[7] = 1./3.; 03253 K[8] = 1; 03254 break; 03255 03256 } 03257 03258 if ((i==j) && (j==k)) 03259 sigma = 1./120.; 03260 03261 else if ((i==j) || (j==k) || (i==k)) 03262 sigma = 1./360.; 03263 03264 else 03265 sigma = 1./720.; 03266 03267 fun += vertex(W, F, R, cell_in, epsilon, w, nvert, K, H, me, 03268 vol, f, lqmin, adp, Gloc, sigma); 03269 03270 g += sigma*lqmin; 03271 if (gqmin > lqmin) 03272 gqmin = lqmin; 03273 } 03274 } 03275 } 03276 } 03277 } 03278 03279 // fixed nodes correction 03280 for (int ii=0; ii<nvert; ii++) 03281 { 03282 if (mask[cell_in[ii]] == 1) 03283 { 03284 for (unsigned kk=0; kk<_dim; kk++) 03285 { 03286 for (int jj=0; jj<nvert; jj++) 03287 { 03288 W[kk][ii][jj] = 0; 03289 W[kk][jj][ii] = 0; 03290 } 03291 03292 W[kk][ii][ii] = 1; 03293 F[kk][ii] = 0; 03294 } 03295 } 03296 } 03297 // end of fixed nodes correction 03298 03299 // Set up return value references 03300 Vmin = g; 03301 qmin = gqmin/vol; 03302 03303 return fun; 03304 } 03305 03306 03307 03308 // avertex - assembly of adaptivity metric on a cell 03309 double VariationalMeshSmoother::avertex(const std::vector<double>& afun, 03310 std::vector<double>& G, 03311 const Array2D<double>& R, 03312 const std::vector<int>& cell_in, 03313 int nvert, 03314 int adp) 03315 { 03316 std::vector<double> a1(3), a2(3), a3(3), qu(3), K(8); 03317 Array2D<double> Q(3, nvert); 03318 03319 for (int i=0; i<8; i++) 03320 K[i] = 0.5; // cell center 03321 03322 basisA(Q, nvert, K, Q, 1); 03323 03324 for (unsigned i=0; i<_dim; i++) 03325 for (int j=0; j<nvert; j++) 03326 { 03327 a1[i] += Q[i][j]*R[cell_in[j]][0]; 03328 a2[i] += Q[i][j]*R[cell_in[j]][1]; 03329 if (_dim == 3) 03330 a3[i] += Q[i][j]*R[cell_in[j]][2]; 03331 03332 qu[i] += Q[i][j]*afun[cell_in[j]]; 03333 } 03334 03335 double det = 0.; 03336 03337 if (_dim == 2) 03338 det = jac2(a1[0], a1[1], 03339 a2[0], a2[1]); 03340 else 03341 det = jac3(a1[0], a1[1], a1[2], 03342 a2[0], a2[1], a2[2], 03343 a3[0], a3[1], a3[2]); 03344 03345 // Return val 03346 double g = 0.; 03347 03348 if (det != 0) 03349 { 03350 if (_dim == 2) 03351 { 03352 double df0 = jac2(qu[0], qu[1], a2[0], a2[1])/det; 03353 double df1 = jac2(a1[0], a1[1], qu[0], qu[1])/det; 03354 g = (1. + df0*df0 + df1*df1); 03355 03356 if (adp == 2) 03357 { 03358 // directional adaptation G=diag(g_i) 03359 G[0] = 1. + df0*df0; 03360 G[1] = 1. + df1*df1; 03361 } 03362 else 03363 { 03364 for (unsigned i=0; i<_dim; i++) 03365 G[i] = g; // simple adaptation G=gI 03366 } 03367 } 03368 else 03369 { 03370 double df0 = (qu[0]*(a2[1]*a3[2]-a2[2]*a3[1]) + qu[1]*(a2[2]*a3[0]-a2[0]*a3[2]) + qu[2]*(a2[0]*a3[1]-a2[1]*a3[0]))/det; 03371 double df1 = (qu[0]*(a3[1]*a1[2]-a3[2]*a1[1]) + qu[1]*(a3[2]*a1[0]-a3[0]*a1[2]) + qu[2]*(a3[0]*a1[1]-a3[1]*a1[0]))/det; 03372 double df2 = (qu[0]*(a1[1]*a2[2]-a1[2]*a2[1]) + qu[1]*(a1[2]*a2[0]-a1[0]*a2[2]) + qu[2]*(a1[0]*a2[1]-a1[1]*a2[0]))/det; 03373 g = 1. + df0*df0 + df1*df1 + df2*df2; 03374 if (adp == 2) 03375 { 03376 // directional adaptation G=diag(g_i) 03377 G[0] = 1. + df0*df0; 03378 G[1] = 1. + df1*df1; 03379 G[2] = 1. + df2*df2; 03380 } 03381 else 03382 { 03383 for (unsigned i=0; i<_dim; i++) 03384 G[i] = g; // simple adaptation G=gI 03385 } 03386 } 03387 } 03388 else 03389 { 03390 g = 1.; 03391 for (unsigned i=0; i<_dim; i++) 03392 G[i] = g; 03393 } 03394 03395 return g; 03396 } 03397 03398 03399 03400 // Computes local matrics W and local rhs F on one basis 03401 double VariationalMeshSmoother::vertex(Array3D<double>& W, 03402 Array2D<double>& F, 03403 const Array2D<double>& R, 03404 const std::vector<int>& cell_in, 03405 double epsilon, 03406 double w, 03407 int nvert, 03408 const std::vector<double>& K, 03409 const Array2D<double>& H, 03410 int me, 03411 double vol, 03412 int f, 03413 double& qmin, 03414 int adp, 03415 const std::vector<double>& g, 03416 double sigma) 03417 { 03418 // hessian, function, gradient 03419 Array2D<double> Q(3, nvert); 03420 basisA(Q, nvert, K, H, me); 03421 03422 std::vector<double> a1(3), a2(3), a3(3); 03423 for (unsigned i=0; i<_dim; i++) 03424 for (int j=0; j<nvert; j++) 03425 { 03426 a1[i] += Q[i][j]*R[cell_in[j]][0]; 03427 a2[i] += Q[i][j]*R[cell_in[j]][1]; 03428 if (_dim == 3) 03429 a3[i] += Q[i][j]*R[cell_in[j]][2]; 03430 } 03431 03432 // account for adaptation 03433 double G = 0.; 03434 if (adp < 2) 03435 G = g[0]; 03436 else 03437 { 03438 G = 1.; 03439 for (unsigned i=0; i<_dim; i++) 03440 { 03441 a1[i] *= std::sqrt(g[0]); 03442 a2[i] *= std::sqrt(g[1]); 03443 if (_dim == 3) 03444 a3[i] *= std::sqrt(g[2]); 03445 } 03446 } 03447 03448 double 03449 det = 0., 03450 tr = 0., 03451 phit = 0.; 03452 03453 std::vector<double> av1(3), av2(3), av3(3); 03454 03455 if (_dim == 2) 03456 { 03457 av1[0] = a2[1]; 03458 av1[1] = -a2[0]; 03459 av2[0] = -a1[1]; 03460 av2[1] = a1[0]; 03461 det = jac2(a1[0], a1[1], a2[0], a2[1]); 03462 for (int i=0; i<2; i++) 03463 tr += 0.5*(a1[i]*a1[i] + a2[i]*a2[i]); 03464 03465 phit = (1-w)*tr + w*0.5*(vol/G + det*det*G/vol); 03466 } 03467 03468 if (_dim == 3) 03469 { 03470 av1[0] = a2[1]*a3[2] - a2[2]*a3[1]; 03471 av1[1] = a2[2]*a3[0] - a2[0]*a3[2]; 03472 av1[2] = a2[0]*a3[1] - a2[1]*a3[0]; 03473 03474 av2[0] = a3[1]*a1[2] - a3[2]*a1[1]; 03475 av2[1] = a3[2]*a1[0] - a3[0]*a1[2]; 03476 av2[2] = a3[0]*a1[1] - a3[1]*a1[0]; 03477 03478 av3[0] = a1[1]*a2[2] - a1[2]*a2[1]; 03479 av3[1] = a1[2]*a2[0] - a1[0]*a2[2]; 03480 av3[2] = a1[0]*a2[1] - a1[1]*a2[0]; 03481 03482 det = jac3(a1[0], a1[1], a1[2], 03483 a2[0], a2[1], a2[2], 03484 a3[0], a3[1], a3[2]); 03485 03486 for (int i=0; i<3; i++) 03487 tr += (1./3.)*(a1[i]*a1[i] + a2[i]*a2[i] + a3[i]*a3[i]); 03488 03489 phit = (1-w)*pow(tr,1.5) + w*0.5*(vol/G + det*det*G/vol); 03490 } 03491 03492 double dchi = 0.5 + det*0.5/std::sqrt(epsilon*epsilon + det*det); 03493 double chi = 0.5*(det + std::sqrt(epsilon*epsilon + det*det)); 03494 double fet = (chi != 0.) ? phit/chi : 1.e32; 03495 03496 // Set return value reference 03497 qmin = det*G; 03498 03499 // gradient and Hessian 03500 if (f == 0) 03501 { 03502 Array3D<double> P(3, 3, 3); 03503 Array3D<double> d2phi(3, 3, 3); 03504 Array2D<double> dphi(3, 3); 03505 Array2D<double> dfe(3, 3); 03506 03507 if (_dim == 2) 03508 { 03509 for (int i=0; i<2; i++) 03510 { 03511 dphi[0][i] = (1-w)*a1[i] + w*G*det*av1[i]/vol; 03512 dphi[1][i] = (1-w)*a2[i] + w*G*det*av2[i]/vol; 03513 } 03514 03515 for (int i=0; i<2; i++) 03516 for (int j=0; j<2; j++) 03517 { 03518 d2phi[0][i][j] = w*G*av1[i]*av1[j]/vol; 03519 d2phi[1][i][j] = w*G*av2[i]*av2[j]/vol; 03520 03521 if (i == j) 03522 for (int k=0; k<2; k++) 03523 d2phi[k][i][j] += 1.-w; 03524 } 03525 03526 for (int i=0; i<2; i++) 03527 { 03528 dfe[0][i] = (dphi[0][i] - fet*dchi*av1[i])/chi; 03529 dfe[1][i] = (dphi[1][i] - fet*dchi*av2[i])/chi; 03530 } 03531 03532 for (int i=0; i<2; i++) 03533 for (int j=0; j<2; j++) 03534 { 03535 P[0][i][j] = (d2phi[0][i][j] - dchi*(av1[i]*dfe[0][j] + dfe[0][i]*av1[j]))/chi; 03536 P[1][i][j] = (d2phi[1][i][j] - dchi*(av2[i]*dfe[1][j] + dfe[1][i]*av2[j]))/chi; 03537 } 03538 } 03539 03540 if (_dim == 3) 03541 { 03542 for (int i=0; i<3; i++) 03543 { 03544 dphi[0][i] = (1-w)*std::sqrt(tr)*a1[i] + w*G*det*av1[i]/vol; 03545 dphi[1][i] = (1-w)*std::sqrt(tr)*a2[i] + w*G*det*av2[i]/vol; 03546 dphi[2][i] = (1-w)*std::sqrt(tr)*a3[i] + w*G*det*av3[i]/vol; 03547 } 03548 03549 for (int i=0; i<3; i++) 03550 { 03551 if (tr != 0) 03552 { 03553 d2phi[0][i][i] = (1-w)/(3.*std::sqrt(tr))*a1[i]*a1[i] + w*G*av1[i]*av1[i]/vol; 03554 d2phi[1][i][i] = (1-w)/(3.*std::sqrt(tr))*a2[i]*a2[i] + w*G*av2[i]*av2[i]/vol; 03555 d2phi[2][i][i] = (1-w)/(3.*std::sqrt(tr))*a3[i]*a3[i] + w*G*av3[i]*av3[i]/vol; 03556 } 03557 else 03558 { 03559 for (int k=0; k<3; k++) 03560 d2phi[k][i][i] = 0.; 03561 } 03562 03563 for (int k=0; k<3; k++) 03564 d2phi[k][i][i] += (1-w)*std::sqrt(tr); 03565 } 03566 03567 const double con = 100.; 03568 03569 for (int i=0; i<3; i++) 03570 { 03571 dfe[0][i] = (dphi[0][i] - fet*dchi*av1[i] + con*epsilon*a1[i])/chi; 03572 dfe[1][i] = (dphi[1][i] - fet*dchi*av2[i] + con*epsilon*a2[i])/chi; 03573 dfe[2][i] = (dphi[2][i] - fet*dchi*av3[i] + con*epsilon*a3[i])/chi; 03574 } 03575 03576 for (int i=0; i<3; i++) 03577 { 03578 P[0][i][i] = (d2phi[0][i][i] - dchi*(av1[i]*dfe[0][i] + dfe[0][i]*av1[i]) + con*epsilon)/chi; 03579 P[1][i][i] = (d2phi[1][i][i] - dchi*(av2[i]*dfe[1][i] + dfe[1][i]*av2[i]) + con*epsilon)/chi; 03580 P[2][i][i] = (d2phi[2][i][i] - dchi*(av3[i]*dfe[2][i] + dfe[2][i]*av3[i]) + con*epsilon)/chi; 03581 } 03582 03583 for (int k=0; k<3; k++) 03584 for (int i=0; i<3; i++) 03585 for (int j=0; j<3; j++) 03586 if (i != j) 03587 P[k][i][j] = 0.; 03588 } 03589 03590 /*--------matrix W, right side F---------------------*/ 03591 Array2D<double> gpr(3, nvert); 03592 03593 for (unsigned i1=0; i1<_dim; i1++) 03594 { 03595 for (unsigned i=0; i<_dim; i++) 03596 for (int j=0; j<nvert; j++) 03597 for (unsigned k=0; k<_dim; k++) 03598 gpr[i][j] += P[i1][i][k]*Q[k][j]; 03599 03600 for (int i=0; i<nvert; i++) 03601 for (int j=0; j<nvert; j++) 03602 for (unsigned k=0; k<_dim; k++) 03603 W[i1][i][j] += Q[k][i]*gpr[k][j]*sigma; 03604 03605 for (int i=0; i<nvert; i++) 03606 for (int k=0; k<2; k++) 03607 F[i1][i] += Q[k][i]*dfe[i1][k]*sigma; 03608 } 03609 } 03610 03611 return fet*sigma; 03612 } 03613 03614 03615 03616 // Solve Symmetric Positive Definite (SPD) linear system 03617 // by Conjugate Gradient (CG) method preconditioned by 03618 // Point Jacobi (diagonal scaling) 03619 int VariationalMeshSmoother::solver(int n, 03620 const std::vector<int>& ia, 03621 const std::vector<int>& ja, 03622 const std::vector<double>& a, 03623 std::vector<double>& x, 03624 const std::vector<double>& b, 03625 double eps, 03626 int maxite, 03627 int msglev) 03628 { 03629 _logfile << "Beginning Solve " << n << std::endl; 03630 03631 // Check parameters 03632 int info = pcg_par_check(n, ia, ja, a, eps, maxite, msglev); 03633 if (info != 0) 03634 return info; 03635 03636 // PJ preconditioner construction 03637 std::vector<double> u(n); 03638 for (int i=0; i<n; i++) 03639 u[i] = 1./a[ia[i]]; 03640 03641 // PCG iterations 03642 std::vector<double> r(n), p(n), z(n); 03643 info = pcg_ic0(n, ia, ja, a, u, x, b, r, p, z, eps, maxite, msglev); 03644 03645 // Mat sparse_global; 03646 // MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,n,n,ia,ja,a,&sparse_global); 03647 03648 _logfile << "Finished Solve " << n << std::endl; 03649 03650 return info; 03651 } 03652 03653 03654 03655 // Input parameter check 03656 int VariationalMeshSmoother::pcg_par_check(int n, 03657 const std::vector<int>& ia, 03658 const std::vector<int>& ja, 03659 const std::vector<double>& a, 03660 double eps, 03661 int maxite, 03662 int msglev) 03663 { 03664 int i, j, jj, k; 03665 03666 if (n <= 0) 03667 { 03668 if (msglev > 0) 03669 _logfile << "sol_pcg: incorrect input parameter: n =" << n << std::endl; 03670 return -1; 03671 } 03672 03673 if (ia[0] != 0) 03674 { 03675 if (msglev > 0) 03676 _logfile << "sol_pcg: incorrect input parameter: ia(1) =" << ia[0] << std::endl; 03677 return -2; 03678 } 03679 03680 for (i=0; i<n; i++) 03681 { 03682 if (ia[i+1] < ia[i]) 03683 { 03684 if (msglev >= 1) 03685 _logfile << "sol_pcg: incorrect input parameter: i =" 03686 << i+1 03687 << "; ia(i) =" 03688 << ia[i] 03689 << " must be <= a(i+1) =" 03690 << ia[i+1] 03691 << std::endl; 03692 return -2; 03693 } 03694 } 03695 03696 for (i=0; i<n; i++) 03697 { 03698 if (ja[ia[i]] != (i+1)) 03699 { 03700 if (msglev >= 1) 03701 _logfile << "sol_pcg: incorrect input parameter: i =" 03702 << i+1 03703 << " ; ia(i) =" 03704 << ia[i] 03705 << " ; absence of diagonal entry; k =" 03706 << ia[i]+1 03707 << " ; the value ja(k) =" 03708 << ja[ia[i]] 03709 << " must be equal to i" 03710 << std::endl; 03711 03712 return -3; 03713 } 03714 03715 jj = 0; 03716 for (k=ia[i]; k<ia[i+1]; k++) 03717 { 03718 j=ja[k]; 03719 if ((j<(i+1)) || (j>n)) 03720 { 03721 if (msglev >= 1) 03722 _logfile << "sol_pcg: incorrect input parameter: i =" 03723 << i+1 03724 << " ; ia(i) =" 03725 << ia[i] 03726 << " ; a(i+1) =" 03727 << ia[i+1] 03728 << " ; k =" 03729 << k+1 03730 << " ; the value ja(k) =" 03731 << ja[k] 03732 << " is out of range" 03733 << std::endl; 03734 03735 return -3; 03736 } 03737 if (j <= jj) 03738 { 03739 if (msglev >= 1) 03740 _logfile << "sol_pcg: incorrect input parameter: i =" 03741 << i+1 03742 << " ; ia(i) =" 03743 << ia[i] 03744 << " ; a(i+1) =" 03745 << ia[i+1] 03746 << " ; k =" 03747 << k+1 03748 << " ; the value ja(k) =" 03749 << ja[k] 03750 << " must be less than ja(k+1) =" 03751 << ja[k+1] 03752 << std::endl; 03753 03754 return -3; 03755 } 03756 jj = j; 03757 } 03758 } 03759 03760 for (i=0; i<n; i++) 03761 { 03762 if (a[ia[i]] <= 0.) 03763 { 03764 if (msglev >= 1) 03765 _logfile << "sol_pcg: incorrect input parameter: i =" 03766 << i+1 03767 << " ; ia(i) =" 03768 << ia[i] 03769 << " ; the diagonal entry a(ia(i)) =" 03770 << a[ia[i]] 03771 << " must be > 0" 03772 << std::endl; 03773 03774 return -4; 03775 } 03776 } 03777 03778 if (eps < 0.) 03779 { 03780 if (msglev > 0) 03781 _logfile << "sol_pcg: incorrect input parameter: eps =" << eps << std::endl; 03782 return -7; 03783 } 03784 03785 if (maxite < 1) 03786 { 03787 if (msglev > 0) 03788 _logfile << "sol_pcg: incorrect input parameter: maxite =" << maxite << std::endl; 03789 return -8; 03790 } 03791 03792 return 0; 03793 } 03794 03795 03796 03797 // Solve the SPD linear system by PCG method 03798 int VariationalMeshSmoother::pcg_ic0(int n, 03799 const std::vector<int>& ia, 03800 const std::vector<int>& ja, 03801 const std::vector<double>& a, 03802 const std::vector<double>& u, 03803 std::vector<double>& x, 03804 const std::vector<double>& b, 03805 std::vector<double>& r, 03806 std::vector<double>& p, 03807 std::vector<double>& z, 03808 double eps, 03809 int maxite, 03810 int msglev) 03811 { 03812 // Return value 03813 int i = 0; 03814 03815 double 03816 rhr = 0., 03817 rhr0 = 0., 03818 rhrold = 0., 03819 rr0 = 0.; 03820 03821 for (i=0; i<=maxite; i++) 03822 { 03823 if (i == 0) 03824 p = x; 03825 03826 // z=Ap 03827 for (int ii=0; ii<n; ii++) 03828 z[ii] = 0.; 03829 03830 for (int ii=0; ii<n; ii++) 03831 { 03832 z[ii] += a[ia[ii]]*p[ii]; 03833 03834 for (int j=ia[ii]+1; j<ia[ii+1]; j++) 03835 { 03836 z[ii] += a[j]*p[ja[j]-1]; 03837 z[ja[j]-1] += a[j]*p[ii]; 03838 } 03839 } 03840 03841 if (i == 0) 03842 for (int k=0; k<n; k++) 03843 r[k] = b[k] - z[k]; // r(0) = b - Ax(0) 03844 03845 if (i > 0) 03846 { 03847 double pap = 0.; 03848 for (int k=0; k<n; k++) 03849 pap += p[k]*z[k]; 03850 03851 double alpha = rhr/pap; 03852 for (int k=0; k<n; k++) 03853 { 03854 x[k] += p[k]*alpha; 03855 r[k] -= z[k]*alpha; 03856 } 03857 rhrold = rhr; 03858 } 03859 03860 // z = H * r 03861 for (int ii=0; ii<n; ii++) 03862 z[ii] = r[ii]*u[ii]; 03863 03864 if (i == 0) 03865 p = z; 03866 03867 rhr = 0.; 03868 double rr = 0.; 03869 for (int k=0; k<n; k++) 03870 { 03871 rhr += r[k]*z[k]; 03872 rr += r[k]*r[k]; 03873 } 03874 03875 if (i == 0) 03876 { 03877 rhr0 = rhr; 03878 rr0 = rr; 03879 } 03880 03881 if (msglev > 0) 03882 _logfile << i 03883 << " ) rHr =" 03884 << std::sqrt(rhr/rhr0) 03885 << " rr =" 03886 << std::sqrt(rr/rr0) 03887 << std::endl; 03888 03889 if (rr <= eps*eps*rr0) 03890 return i; 03891 03892 if (i >= maxite) 03893 return i; 03894 03895 if (i > 0) 03896 { 03897 double beta = rhr/rhrold; 03898 for (int k=0; k<n; k++) 03899 p[k] = z[k] + p[k]*beta; 03900 } 03901 } // end for i 03902 03903 return i; 03904 } 03905 03906 03907 03908 03909 // Sample mesh file generation 03910 void VariationalMeshSmoother::gener(char grid[], 03911 int n) 03912 { 03913 const int n1 = 3; 03914 03915 int 03916 N = 1, 03917 ncells = 1; 03918 03919 for (int i=0; i<n; i++) 03920 { 03921 N *= n1; 03922 ncells *= (n1-1); 03923 } 03924 03925 const double x = 1./static_cast<double>(n1-1); 03926 03927 std::ofstream outfile(grid); 03928 03929 outfile << n << "\n" << N << "\n" << ncells << "\n0\n" << std::endl; 03930 03931 for (int i=0; i<N; i++) 03932 { 03933 // node coordinates 03934 int k = i; 03935 int mask = 0; 03936 for (int j=0; j<n; j++) 03937 { 03938 int ii = k % n1; 03939 if ((ii == 0) || (ii == n1-1)) 03940 mask = 1; 03941 03942 outfile << static_cast<double>(ii)*x << " "; 03943 k /= n1; 03944 } 03945 outfile << mask << std::endl; 03946 } 03947 03948 for (int i=0; i<ncells; i++) 03949 { 03950 // cell connectivity 03951 int nc = i; 03952 int ii = nc%(n1-1); 03953 nc /= (n1-1); 03954 int jj = nc%(n1-1); 03955 int kk = nc/(n1-1); 03956 03957 if (n == 2) 03958 outfile << ii+n1*jj << " " 03959 << ii+1+jj*n1 << " " 03960 << ii+(jj+1)*n1 << " " 03961 << ii+1+(jj+1)*n1 << " "; 03962 03963 if (n == 3) 03964 outfile << ii+n1*jj+n1*n1*kk << " " 03965 << ii+1+jj*n1+n1*n1*kk << " " 03966 << ii+(jj+1)*n1+n1*n1*kk << " " 03967 << ii+1+(jj+1)*n1+n1*n1*kk << " " 03968 << ii+n1*jj+n1*n1*(kk+1) << " " 03969 << ii+1+jj*n1+n1*n1*(kk+1) << " " 03970 << ii+(jj+1)*n1+n1*n1*(kk+1) << " " 03971 << ii+1+(jj+1)*n1+n1*n1*(kk+1) << " "; 03972 03973 outfile << "-1 -1 0 \n"; 03974 } 03975 } 03976 03977 03978 03979 // Metric Generation 03980 void VariationalMeshSmoother::metr_data_gen(std::string grid, 03981 std::string metr, 03982 int me) 03983 { 03984 double det, g1, g2, g3, det_o, g1_o, g2_o, g3_o, eps=1e-3; 03985 03986 std::vector<double> K(9); 03987 Array2D<double> Q(3, 3*_dim + _dim%2); 03988 03989 // Use _mesh to determine N and ncells 03990 this->_n_nodes = _mesh.n_nodes(); 03991 this->_n_cells = _mesh.n_active_elem(); 03992 03993 std::vector<int> 03994 mask(_n_nodes), 03995 mcells(_n_cells); 03996 03997 Array2D<int> cells(_n_cells, 3*_dim + _dim%2); 03998 Array2D<double> R(_n_nodes,_dim); 03999 04000 readgr(R, mask, cells, mcells, mcells, mcells); 04001 04002 // genetrate metric file 04003 std::ofstream metric_file(metr.c_str()); 04004 if (!metric_file.good()) 04005 libmesh_error_msg("Error opening metric output file."); 04006 04007 // Use scientific notation with 6 digits 04008 metric_file << std::scientific << std::setprecision(6); 04009 04010 int Ncells = 0; 04011 det_o = 1.; 04012 g1_o = 1.; 04013 g2_o = 1.; 04014 g3_o = 1.; 04015 for (unsigned i=0; i<_n_cells; i++) 04016 if (mcells[i] >= 0) 04017 { 04018 int nvert=0; 04019 while (cells[i][nvert] >= 0) 04020 nvert++; 04021 04022 if (_dim == 2) 04023 { 04024 // 2D - tri and quad 04025 if (nvert == 3) 04026 { 04027 // tri 04028 basisA(Q, 3, K, Q, 1); 04029 04030 Point a1, a2; 04031 for (int k=0; k<2; k++) 04032 for (int l=0; l<3; l++) 04033 { 04034 a1(k) += Q[k][l]*R[cells[i][l]][0]; 04035 a2(k) += Q[k][l]*R[cells[i][l]][1]; 04036 } 04037 04038 det = jac2(a1(0), a1(1), a2(0), a2(1)); 04039 g1 = std::sqrt(a1(0)*a1(0) + a2(0)*a2(0)); 04040 g2 = std::sqrt(a1(1)*a1(1) + a2(1)*a2(1)); 04041 04042 // need to keep data from previous cell 04043 if ((std::abs(det) < eps*eps*det_o) || (det < 0)) 04044 det = det_o; 04045 04046 if ((std::abs(g1) < eps*g1_o) || (g1<0)) 04047 g1 = g1_o; 04048 04049 if ((std::abs(g2) < eps*g2_o) || (g2<0)) 04050 g2 = g2_o; 04051 04052 // write to file 04053 if (me == 2) 04054 metric_file << 1./std::sqrt(det) 04055 << " 0.000000e+00 \n0.000000e+00 " 04056 << 1./std::sqrt(det) 04057 << std::endl; 04058 04059 if (me == 3) 04060 metric_file << 1./g1 04061 << " 0.000000e+00 \n0.000000e+00 " 04062 << 1./g2 04063 << std::endl; 04064 04065 det_o = det; 04066 g1_o = g1; 04067 g2_o = g2; 04068 Ncells++; 04069 } 04070 04071 if (nvert == 4) 04072 { 04073 // quad 04074 04075 // Set up the node edge neighbor indices 04076 const unsigned node_indices[4] = {0, 1, 3, 2}; 04077 const unsigned first_neighbor_indices[4] = {1, 3, 2, 0}; 04078 const unsigned second_neighbor_indices[4] = {2, 0, 1, 3}; 04079 04080 // Loop over each node, compute some quantities associated 04081 // with its edge neighbors, and write them to file. 04082 for (unsigned ni=0; ni<4; ++ni) 04083 { 04084 unsigned 04085 node_index = node_indices[ni], 04086 first_neighbor_index = first_neighbor_indices[ni], 04087 second_neighbor_index = second_neighbor_indices[ni]; 04088 04089 Real 04090 node_x = R[cells[i][node_index]][0], 04091 node_y = R[cells[i][node_index]][1], 04092 first_neighbor_x = R[cells[i][first_neighbor_index]][0], 04093 first_neighbor_y = R[cells[i][first_neighbor_index]][1], 04094 second_neighbor_x = R[cells[i][second_neighbor_index]][0], 04095 second_neighbor_y = R[cells[i][second_neighbor_index]][1]; 04096 04097 04098 // "dx" 04099 Point a1(first_neighbor_x - node_x, 04100 second_neighbor_x - node_x); 04101 04102 // "dy" 04103 Point a2(first_neighbor_y - node_y, 04104 second_neighbor_y - node_y); 04105 04106 det = jac2(a1(0), a1(1), a2(0), a2(1)); 04107 g1 = std::sqrt(a1(0)*a1(0) + a2(0)*a2(0)); 04108 g2 = std::sqrt(a1(1)*a1(1) + a2(1)*a2(1)); 04109 04110 // need to keep data from previous cell 04111 if ((std::abs(det) < eps*eps*det_o) || (det < 0)) 04112 det = det_o; 04113 04114 if ((std::abs(g1) < eps*g1_o) || (g1 < 0)) 04115 g1 = g1_o; 04116 04117 if ((std::abs(g2) < eps*g2_o) || (g2 < 0)) 04118 g2 = g2_o; 04119 04120 // write to file 04121 if (me == 2) 04122 metric_file << 1./std::sqrt(det) << " " 04123 << 0.5/std::sqrt(det) << " \n0.000000e+00 " 04124 << 0.5*std::sqrt(3./det) 04125 << std::endl; 04126 04127 if (me == 3) 04128 metric_file << 1./g1 << " " 04129 << 0.5/g2 << "\n0.000000e+00 " 04130 << 0.5*std::sqrt(3.)/g2 04131 << std::endl; 04132 04133 det_o = det; 04134 g1_o = g1; 04135 g2_o = g2; 04136 Ncells++; 04137 } 04138 } // end QUAD case 04139 } // end _dim==2 04140 04141 if (_dim == 3) 04142 { 04143 // 3D - tetr and hex 04144 04145 if (nvert == 4) 04146 { 04147 // tetr 04148 basisA(Q, 4, K, Q, 1); 04149 04150 Point a1, a2, a3; 04151 04152 for (int k=0; k<3; k++) 04153 for (int l=0; l<4; l++) 04154 { 04155 a1(k) += Q[k][l]*R[cells[i][l]][0]; 04156 a2(k) += Q[k][l]*R[cells[i][l]][1]; 04157 a3(k) += Q[k][l]*R[cells[i][l]][2]; 04158 } 04159 04160 det = jac3(a1(0), a1(1), a1(2), 04161 a2(0), a2(1), a2(2), 04162 a3(0), a3(1), a3(2)); 04163 g1 = std::sqrt(a1(0)*a1(0) + a2(0)*a2(0) + a3(0)*a3(0)); 04164 g2 = std::sqrt(a1(1)*a1(1) + a2(1)*a2(1) + a3(1)*a3(1)); 04165 g3 = std::sqrt(a1(2)*a1(2) + a2(2)*a2(2) + a3(2)*a3(2)); 04166 04167 // need to keep data from previous cell 04168 if ((std::abs(det) < eps*eps*eps*det_o) || (det < 0)) 04169 det = det_o; 04170 04171 if ((std::abs(g1) < eps*g1_o) || (g1 < 0)) 04172 g1 = g1_o; 04173 04174 if ((std::abs(g2) < eps*g2_o) || (g2 < 0)) 04175 g2 = g2_o; 04176 04177 if ((std::abs(g3) < eps*g3_o) || (g3 < 0)) 04178 g3 = g3_o; 04179 04180 // write to file 04181 if (me == 2) 04182 metric_file << 1./pow(det, 1./3.) 04183 << " 0.000000e+00 0.000000e+00\n0.000000e+00 " 04184 << 1./pow(det, 1./3.) 04185 << " 0.000000e+00\n0.000000e+00 0.000000e+00 " 04186 << 1./pow(det, 1./3.) 04187 << std::endl; 04188 04189 if (me == 3) 04190 metric_file << 1./g1 04191 << " 0.000000e+00 0.000000e+00\n0.000000e+00 " 04192 << 1./g2 04193 << " 0.000000e+00\n0.000000e+00 0.000000e+00 " 04194 << 1./g3 04195 << std::endl; 04196 04197 det_o = det; 04198 g1_o = g1; 04199 g2_o = g2; 04200 g3_o = g3; 04201 Ncells++; 04202 } 04203 04204 if (nvert == 8) 04205 { 04206 // hex 04207 04208 // Set up the node edge neighbor indices 04209 const unsigned node_indices[8] = {0, 1, 3, 2, 4, 5, 7, 6}; 04210 const unsigned first_neighbor_indices[8] = {1, 3, 2, 0, 6, 4, 5, 7}; 04211 const unsigned second_neighbor_indices[8] = {2, 0, 1, 3, 5, 7, 6, 4}; 04212 const unsigned third_neighbor_indices[8] = {4, 5, 7, 6, 0, 1, 3, 2}; 04213 04214 // Loop over each node, compute some quantities associated 04215 // with its edge neighbors, and write them to file. 04216 for (unsigned ni=0; ni<8; ++ni) 04217 { 04218 unsigned 04219 node_index = node_indices[ni], 04220 first_neighbor_index = first_neighbor_indices[ni], 04221 second_neighbor_index = second_neighbor_indices[ni], 04222 third_neighbor_index = third_neighbor_indices[ni]; 04223 04224 Real 04225 node_x = R[cells[i][node_index]][0], 04226 node_y = R[cells[i][node_index]][1], 04227 node_z = R[cells[i][node_index]][2], 04228 first_neighbor_x = R[cells[i][first_neighbor_index]][0], 04229 first_neighbor_y = R[cells[i][first_neighbor_index]][1], 04230 first_neighbor_z = R[cells[i][first_neighbor_index]][2], 04231 second_neighbor_x = R[cells[i][second_neighbor_index]][0], 04232 second_neighbor_y = R[cells[i][second_neighbor_index]][1], 04233 second_neighbor_z = R[cells[i][second_neighbor_index]][2], 04234 third_neighbor_x = R[cells[i][third_neighbor_index]][0], 04235 third_neighbor_y = R[cells[i][third_neighbor_index]][1], 04236 third_neighbor_z = R[cells[i][third_neighbor_index]][2]; 04237 04238 // "dx" 04239 Point a1(first_neighbor_x - node_x, 04240 second_neighbor_x - node_x, 04241 third_neighbor_x - node_x); 04242 04243 // "dy" 04244 Point a2(first_neighbor_y - node_y, 04245 second_neighbor_y - node_y, 04246 third_neighbor_y - node_y); 04247 04248 // "dz" 04249 Point a3(first_neighbor_z - node_z, 04250 second_neighbor_z - node_z, 04251 third_neighbor_z - node_z); 04252 04253 det = jac3(a1(0), a1(1), a1(2), 04254 a2(0), a2(1), a2(2), 04255 a3(0), a3(1), a3(2)); 04256 g1 = std::sqrt(a1(0)*a1(0) + a2(0)*a2(0) + a3(0)*a3(0)); 04257 g2 = std::sqrt(a1(1)*a1(1) + a2(1)*a2(1) + a3(1)*a3(1)); 04258 g3 = std::sqrt(a1(2)*a1(2) + a2(2)*a2(2) + a3(2)*a3(2)); 04259 04260 // need to keep data from previous cell 04261 if ((std::abs(det) < eps*eps*eps*det_o) || (det < 0)) 04262 det = det_o; 04263 04264 if ((std::abs(g1) < eps*g1_o) || (g1 < 0)) 04265 g1 = g1_o; 04266 04267 if ((std::abs(g2) < eps*g2_o) || (g2 < 0)) 04268 g2 = g2_o; 04269 04270 if ((std::abs(g3) < eps*g3_o) || (g3 < 0)) 04271 g3 = g3_o; 04272 04273 // write to file 04274 if (me == 2) 04275 metric_file << 1./pow(det, 1./3.) << " " 04276 << 0.5/pow(det, 1./3.) << " " 04277 << 0.5/pow(det, 1./3.) << "\n0.000000e+00 " 04278 << 0.5*std::sqrt(3.)/pow(det, 1./3.) << " " 04279 << 0.5/(std::sqrt(3.)*pow(det, 1./3.)) << "\n0.000000e+00 0.000000e+00 " 04280 << std::sqrt(2/3.)/pow(det, 1./3.) 04281 << std::endl; 04282 04283 if (me == 3) 04284 metric_file << 1./g1 << " " 04285 << 0.5/g2 << " " 04286 << 0.5/g3 << "\n0.000000e+00 " 04287 << 0.5*std::sqrt(3.)/g2 << " " 04288 << 0.5/(std::sqrt(3.)*g3) << "\n0.000000e+00 0.000000e+00 " 04289 << std::sqrt(2./3.)/g3 04290 << std::endl; 04291 04292 det_o = det; 04293 g1_o = g1; 04294 g2_o = g2; 04295 g3_o = g3; 04296 Ncells++; 04297 } // end for ni 04298 } // end hex 04299 } // end dim==3 04300 } 04301 04302 // Done with the metric file 04303 metric_file.close(); 04304 04305 std::ofstream grid_file(grid.c_str()); 04306 if (!grid_file.good()) 04307 libmesh_error_msg("Error opening file: " << grid); 04308 04309 grid_file << _dim << "\n" << _n_nodes << "\n" << Ncells << "\n0" << std::endl; 04310 04311 // Use scientific notation with 6 digits 04312 grid_file << std::scientific << std::setprecision(6); 04313 04314 for (dof_id_type i=0; i<_n_nodes; i++) 04315 { 04316 // node coordinates 04317 for (unsigned j=0; j<_dim; j++) 04318 grid_file << R[i][j] << " "; 04319 04320 grid_file << mask[i] << std::endl; 04321 } 04322 04323 for (dof_id_type i=0; i<_n_cells; i++) 04324 if (mcells[i] >= 0) 04325 { 04326 // cell connectivity 04327 int nvert = 0; 04328 while (cells[i][nvert] >= 0) 04329 nvert++; 04330 04331 if ((nvert == 3) || ((_dim == 3) && (nvert == 4))) 04332 { 04333 // tri & tetr 04334 for (int j=0; j<nvert; j++) 04335 grid_file << cells[i][j] << " "; 04336 04337 for (unsigned j=nvert; j<3*_dim + _dim%2; j++) 04338 grid_file << "-1 "; 04339 04340 grid_file << mcells[i] << std::endl; 04341 } 04342 04343 if ((_dim == 2) && (nvert == 4)) 04344 { 04345 // quad 04346 grid_file << cells[i][0] << " " << cells[i][1] << " " << cells[i][2] << " -1 -1 -1 0" << std::endl; 04347 grid_file << cells[i][1] << " " << cells[i][3] << " " << cells[i][0] << " -1 -1 -1 0" << std::endl; 04348 grid_file << cells[i][3] << " " << cells[i][2] << " " << cells[i][1] << " -1 -1 -1 0" << std::endl; 04349 grid_file << cells[i][2] << " " << cells[i][0] << " " << cells[i][3] << " -1 -1 -1 0" << std::endl; 04350 } 04351 04352 if (nvert == 8) 04353 { 04354 // hex 04355 grid_file << cells[i][0] << " " << cells[i][1] << " " << cells[i][2] << " " << cells[i][4] << " -1 -1 -1 -1 -1 -1 0" << std::endl; 04356 grid_file << cells[i][1] << " " << cells[i][3] << " " << cells[i][0] << " " << cells[i][5] << " -1 -1 -1 -1 -1 -1 0" << std::endl; 04357 grid_file << cells[i][3] << " " << cells[i][2] << " " << cells[i][1] << " " << cells[i][7] << " -1 -1 -1 -1 -1 -1 0" << std::endl; 04358 grid_file << cells[i][2] << " " << cells[i][0] << " " << cells[i][3] << " " << cells[i][6] << " -1 -1 -1 -1 -1 -1 0" << std::endl; 04359 grid_file << cells[i][4] << " " << cells[i][6] << " " << cells[i][5] << " " << cells[i][0] << " -1 -1 -1 -1 -1 -1 0" << std::endl; 04360 grid_file << cells[i][5] << " " << cells[i][4] << " " << cells[i][7] << " " << cells[i][1] << " -1 -1 -1 -1 -1 -1 0" << std::endl; 04361 grid_file << cells[i][7] << " " << cells[i][5] << " " << cells[i][6] << " " << cells[i][3] << " -1 -1 -1 -1 -1 -1 0" << std::endl; 04362 grid_file << cells[i][6] << " " << cells[i][7] << " " << cells[i][4] << " " << cells[i][2] << " -1 -1 -1 -1 -1 -1 0" << std::endl; 04363 } 04364 } 04365 } 04366 04367 } // namespace libMesh 04368 04369 #endif // LIBMESH_ENABLE_VSMOOTHER