49 #include <Eigen/Dense>
86 MPI_Comm_size(_mesh->get_mpi_comm(), &nprocs);
87 MPI_Comm_rank(_mesh->get_mpi_comm(), &rank);
91 for(
int i=0;i<dim;i++){
93 bbox[i*2+1] = -DBL_MAX;
98 for(
int i=0;i<dim;i++){
100 lbbox[i*2+1] = -DBL_MAX;
102 #pragma omp for schedule(static)
103 for(
int i=0; i<_NNodes; i++){
104 const real_t *x = _mesh->get_coords(i);
106 for(
int j=0;j<dim;j++){
107 lbbox[j*2] = std::min(lbbox[j*2], x[j]);
108 lbbox[j*2+1] = std::max(lbbox[j*2+1], x[j]);
114 for(
int j=0;j<dim;j++){
115 bbox[j*2] = std::min(lbbox[j*2], bbox[j*2]);
116 bbox[j*2+1] = std::max(lbbox[j*2+1], bbox[j*2+1]);
120 double max_extent = bbox[1]-bbox[0];
121 for(
int j=1;j<dim;j++)
122 max_extent = std::max(max_extent, bbox[j*2+1]-bbox[j*2]);
124 min_eigenvalue = 1.0/pow(max_extent, 2);
139 std::cerr<<
"ERROR: void generate_mesh_metric() not yet implemented in 2D.\n";
144 double alpha = pow(1.0/resolution_scaling_factor, 2);
145 #pragma omp for schedule(static)
146 for(
int i=0; i<_NNodes; i++){
166 Eigen::Matrix<double, 6, 6>
A = Eigen::Matrix<real_t, 6, 6>::Zero(6,6);
167 Eigen::Matrix<double, 6, 1>
b = Eigen::Matrix<real_t, 6, 1>::Zero(6);
169 std::vector<index_t> nodes = _mesh->NNList[i];
172 for(
typename std::vector<index_t>::const_iterator it=nodes.begin();it!=nodes.end();++it){
173 const real_t *X0=_mesh->get_coords(*it);
174 real_t x0=X0[0], y0=X0[1], z0=X0[2];
175 assert(std::isfinite(x0));
176 assert(std::isfinite(y0));
177 assert(std::isfinite(z0));
179 for(
typename std::vector<index_t>::const_iterator n=_mesh->NNList[*it].begin();n!=_mesh->NNList[*it].end();++n){
183 const real_t *X=_mesh->get_coords(*n);
184 real_t x=X[0]-x0, y=X[1]-y0, z=X[2]-z0;
186 assert(std::isfinite(x));
187 assert(std::isfinite(y));
188 assert(std::isfinite(z));
194 A[0]+=pow(x, 4); A[1]+=pow(x, 2)*pow(y, 2); A[2]+=pow(x, 2)*pow(z, 2); A[3]+=pow(x, 2)*y*z; A[4]+=pow(x, 3)*z; A[5]+=pow(x, 3)*y;
195 A[6]+=pow(x, 2)*pow(y, 2); A[7]+=pow(y, 4); A[8]+=pow(y, 2)*pow(z, 2); A[9]+=pow(y, 3)*z; A[10]+=x*pow(y, 2)*z; A[11]+=x*pow(y, 3);
196 A[12]+=pow(x, 2)*pow(z, 2); A[13]+=pow(y, 2)*pow(z, 2); A[14]+=pow(z, 4); A[15]+=y*pow(z, 3); A[16]+=x*pow(z, 3); A[17]+=x*y*pow(z, 2);
197 A[18]+=pow(x, 2)*y*z; A[19]+=pow(y, 3)*z; A[20]+=y*pow(z, 3); A[21]+=pow(y, 2)*pow(z, 2); A[22]+=x*y*pow(z, 2); A[23]+=x*pow(y, 2)*z;
198 A[24]+=pow(x, 3)*z; A[25]+=x*pow(y, 2)*z; A[26]+=x*pow(z, 3); A[27]+=x*y*pow(z, 2); A[28]+=pow(x, 2)*pow(z, 2); A[29]+=pow(x, 2)*y*z;
199 A[30]+=pow(x, 3)*y; A[31]+=x*pow(y, 3); A[32]+=x*y*pow(z, 2); A[33]+=x*pow(y, 2)*z; A[34]+=pow(x, 2)*y*z; A[35]+=pow(x, 2)*pow(y, 2);
210 Eigen::Matrix<double, 6, 1>
S = Eigen::Matrix<real_t, 6, 1>::Zero(6);
212 A.svd().solve(b, &S);
214 if(_mesh->NNList[i].size()>=6){
215 sm[0] = S[0]; sm[1] = S[5]; sm[2] = S[4];
216 sm[3] = S[1]; sm[4] = S[3];
219 sm[0] = S[0]; sm[1] = 0; sm[2] = 0;
220 sm[3] = S[1]; sm[4] = 0;
236 std::cerr<<
"ERROR: void generate_Steiner_ellipse() not yet implemented in 2D.\n";
239 std::vector<double> SteinerMetricField(_NElements*6);
242 #pragma omp for schedule(static)
243 for(
int i=0; i<_NElements; i++){
244 const index_t *n=_mesh->get_element(i);
246 const real_t *x0 = _mesh->get_coords(n[0]);
247 const real_t *
x1 = _mesh->get_coords(n[1]);
248 const real_t *
x2 = _mesh->get_coords(n[2]);
249 const real_t *
x3 = _mesh->get_coords(n[3]);
254 double alpha = pow(1.0/resolution_scaling_factor, 2);
255 #pragma omp for schedule(static)
256 for(
int i=0; i<_NNodes; i++){
261 for(
typename std::set<index_t>::const_iterator ie=_mesh->NEList[i].begin();ie!=_mesh->NEList[i].end();++ie){
263 sm[j]+=SteinerMetricField[(*ie)*6+j];
266 double scale = alpha/_mesh->NEList[i].size();
283 #pragma omp for schedule(static)
284 for(
int i=0; i<_NNodes; i++){
297 for(
int i=0; i<_NNodes; i++){
309 real_t m[dim==2?3:6];
310 for(
int i=0; i<_NNodes; i++){
312 m[0] = metric[i*4]; m[1] = metric[i*4+1];
313 m[2] = metric[i*4+3];
315 m[0] = metric[i*9]; m[1] = metric[i*9+1]; m[2] = metric[i*9+2];
316 m[3] = metric[i*9+4]; m[4] = metric[i*9+5];
317 m[5] = metric[i*9+8];
337 assert(_metric!=NULL);
344 if(pNElements > _mesh->NElements){
353 pNElements = _mesh->NElements * fudge;
358 size_t pNNodes = pNElements/(dim==2?2:6);
360 _mesh->_ENList.resize(pNElements*(dim+1));
361 _mesh->boundary.resize(pNElements*(dim+1));
362 _mesh->_coords.resize(pNNodes*dim);
363 _mesh->metric.resize(pNNodes*(dim==2?3:6));
364 _mesh->NNList.resize(pNNodes);
365 _mesh->NEList.resize(pNNodes);
366 _mesh->node_owner.resize(pNNodes, -1);
367 _mesh->lnn2gnn.resize(pNNodes, -1);
372 _mesh->create_gappy_global_numbering(pNElements);
378 #pragma omp for schedule(static)
379 for(
int i=0; i<_NNodes; i++){
380 double M[dim==2?3:6];
382 for(
int j=0; j<(dim==2?3:6); j++)
383 _mesh->metric[i*(dim==2?3:6)+j] = (1.0-omega)*_mesh->metric[i*(dim==2?3:6)+j] + omega*
M[j];
389 halo_update<double, (dim==2?3:6)>(_mesh->get_mpi_comm(), _mesh->send, _mesh->recv, _mesh->metric);
395 assert(_metric!=NULL);
402 if(pNElements > _mesh->NElements){
411 pNElements = _mesh->NElements * fudge;
416 size_t pNNodes = std::max(pNElements/(dim==2?2:6), _mesh->get_number_nodes());
418 _mesh->_ENList.resize(pNElements*(dim+1));
419 _mesh->boundary.resize(pNElements*(dim+1));
420 _mesh->_coords.resize(pNNodes*dim);
421 _mesh->metric.resize(pNNodes*(dim==2?3:6));
422 _mesh->NNList.resize(pNNodes);
423 _mesh->NEList.resize(pNNodes);
424 _mesh->node_owner.resize(pNNodes, -1);
425 _mesh->lnn2gnn.resize(pNNodes, -1);
430 _mesh->create_gappy_global_numbering(pNElements);
436 #pragma omp for schedule(static)
437 for(
int i=0; i<_NNodes; i++){
438 _metric[i].
get_metric(&(_mesh->metric[i*(dim==2?3:6)]));
443 halo_update<double, (dim==2?3:6)>(_mesh->get_mpi_comm(), _mesh->send, _mesh->recv, _mesh->metric);
454 void add_field(
const real_t* psi,
const real_t target_error,
int p_norm=-1){
461 real_t eta = 1.0/target_error;
465 double h[dim==2?3:6];
468 #pragma omp for schedule(static) nowait
469 for(
int i=0; i<_NNodes; i++){
470 hessian_qls_kernel(psi, i, h);
476 m_det = fabs(h[0]*h[2]-h[1]*h[1]);
489 m_det = fabs(h[0]*h[3]*h[5] - h[0]*pow(h[4], 2) - pow(h[1], 2)*h[5] + 2*h[1]*h[2]*h[4] - pow(h[2], 2)*h[3]);
492 double scaling_factor = eta * pow(m_det+DBL_EPSILON, -1.0 / (2.0 * p_norm + dim));
494 if(std::isnormal(scaling_factor)){
495 for(
int j=0;j<(dim==2?3:6);j++)
496 h[j] *= scaling_factor;
499 h[0] = min_eigenvalue; h[1] = 0.0;
500 h[2] = min_eigenvalue;
502 h[0] = min_eigenvalue; h[1] = 0.0; h[2] = 0.0;
503 h[3] = min_eigenvalue; h[4] = 0.0;
504 h[5] = min_eigenvalue;
516 #pragma omp for schedule(static)
517 for(
int i=0; i<_NNodes; i++){
518 hessian_qls_kernel(psi, i, h);
520 for(
int j=0; j<(dim==2?3:6); j++)
538 real_t
M[dim==2?3:6];
539 real_t m = 1.0/(max_len*max_len);
556 #pragma omp for schedule(static)
557 for(
int i=0;i<_NNodes;i++)
558 _metric[i].constrain(&(
M[0]));
566 real_t
M[dim==2?3:6];
567 double m = 1.0/(min_len*min_len);
584 #pragma omp for schedule(static)
585 for(
int i=0;i<_NNodes;i++)
586 _metric[i].constrain(
M,
false);
596 real_t
M[dim==2?3:6];
597 #pragma omp for schedule(static)
598 for(
int n=0;n<_NNodes;n++){
599 double m = 1.0/(min_len[n]*min_len[n]);
625 #pragma omp for schedule(static)
626 for(
int i=0;i<_NNodes;i++)
627 _metric[i].limit_aspect_ratio(max_aspect_ratio);
636 if(predicted>nelements)
645 if(predicted<nelements)
655 scale_factor = pow(scale_factor, 2.0/3.0);
659 #pragma omp for schedule(static)
660 for(
int i=0;i<_NNodes;i++)
661 _metric[i].scale(scale_factor);
671 real_t total_area_metric = 0.0;
673 const real_t inv3=1.0/3.0;
675 const real_t *refx0 = _mesh->get_coords(_mesh->get_element(0)[0]);
676 const real_t *refx1 = _mesh->get_coords(_mesh->get_element(0)[1]);
677 const real_t *refx2 = _mesh->get_coords(_mesh->get_element(0)[2]);
680 #pragma omp parallel for reduction(+:total_area_metric)
681 for(
int i=0;i<_NElements;i++){
682 const index_t *n=_mesh->get_element(i);
684 const real_t *x0 = _mesh->get_coords(n[0]);
685 const real_t *
x1 = _mesh->get_coords(n[1]);
686 const real_t *
x2 = _mesh->get_coords(n[2]);
687 real_t area =
property.area(x0, x1, x2);
693 real_t m00 = (m0[0]+m1[0]+m2[0])*inv3;
694 real_t m01 = (m0[1]+m1[1]+m2[1])*inv3;
695 real_t m11 = (m0[2]+m1[2]+m2[2])*inv3;
697 real_t det = m00*m11-m01*m01;
699 total_area_metric += area*sqrt(det);
706 const real_t smallest_ideal_area = 0.5*(sqrt(3.0)/4.0);
707 predicted = total_area_metric/smallest_ideal_area;
710 real_t total_volume_metric = 0.0;
712 const real_t *refx0 = _mesh->get_coords(_mesh->get_element(0)[0]);
713 const real_t *refx1 = _mesh->get_coords(_mesh->get_element(0)[1]);
714 const real_t *refx2 = _mesh->get_coords(_mesh->get_element(0)[2]);
715 const real_t *refx3 = _mesh->get_coords(_mesh->get_element(0)[3]);
718 #pragma omp parallel for reduction(+:total_volume_metric)
719 for(
int i=0;i<_NElements;i++){
720 const index_t *n=_mesh->get_element(i);
722 const real_t *x0 = _mesh->get_coords(n[0]);
723 const real_t *
x1 = _mesh->get_coords(n[1]);
724 const real_t *
x2 = _mesh->get_coords(n[2]);
725 const real_t *
x3 = _mesh->get_coords(n[3]);
726 real_t volume =
property.volume(x0, x1, x2, x3);
733 real_t m00 = (m0[0]+m1[0]+m2[0]+m3[0])*0.25;
734 real_t m01 = (m0[1]+m1[1]+m2[1]+m3[1])*0.25;
735 real_t m02 = (m0[2]+m1[2]+m2[2]+m3[2])*0.25;
736 real_t m11 = (m0[3]+m1[3]+m2[3]+m3[3])*0.25;
737 real_t m12 = (m0[4]+m1[4]+m2[4]+m3[4])*0.25;
738 real_t m22 = (m0[5]+m1[5]+m2[5]+m3[5])*0.25;
740 real_t det = (m11*m22 - m12*m12)*m00 - (m01*m22 - m02*m12)*m01 + (m01*m12 - m02*m11)*m02;
742 assert(det>-DBL_EPSILON);
743 total_volume_metric += volume*sqrt(det);
747 real_t ideal_volume = 1.0/sqrt(72.0);
748 predicted = total_volume_metric/ideal_volume;
761 MPI_Allreduce(MPI_IN_PLACE, &predicted, 1, _mesh->MPI_REAL_T, MPI_SUM, _mesh->get_mpi_comm());
771 void hessian_qls_kernel(
const real_t *psi,
int i, real_t *Hessian){
772 int min_patch_size = (dim==2?6:15);
774 std::set<index_t> patch = _mesh->get_node_patch(i, min_patch_size);
781 Eigen::Matrix<real_t, 6, 6>
A = Eigen::Matrix<real_t, 6, 6>::Zero(6,6);
782 Eigen::Matrix<real_t, 6, 1>
b = Eigen::Matrix<real_t, 6, 1>::Zero(6);
784 real_t x0=_mesh->_coords[i*2], y0=_mesh->_coords[i*2+1];
786 for(
typename std::set<index_t>::const_iterator n=patch.begin(); n!=patch.end(); n++){
787 real_t x=_mesh->_coords[(*n)*2]-x0, y=_mesh->_coords[(*n)*2+1]-y0;
790 A[6]+=x*x*y*y; A[7]+=x*x*x*x;
791 A[12]+=x*y*y*y; A[13]+=x*x*x*y; A[14]+=x*x*y*y;
792 A[18]+=y*y*y; A[19]+=x*x*y; A[20]+=x*y*y; A[21]+=y*y;
793 A[24]+=x*y*y; A[25]+=x*x*x; A[26]+=x*x*y; A[27]+=x*y; A[28]+=x*x;
794 A[30]+=y*y; A[31]+=x*x; A[32]+=x*y; A[33]+=y; A[34]+=x; A[35]+=1;
796 b[0]+=psi[*n]*y*y; b[1]+=psi[*n]*x*x; b[2]+=psi[*n]*x*y; b[3]+=psi[*n]*y; b[4]+=psi[*n]*x; b[5]+=psi[*n];
798 A[1] = A[6]; A[2] = A[12]; A[3] = A[18]; A[4] = A[24]; A[5] = A[30];
799 A[8] = A[13]; A[9] = A[19]; A[10]= A[25]; A[11]= A[31];
800 A[15]= A[20]; A[16]= A[26]; A[17]= A[32];
801 A[22]= A[27]; A[23]= A[33];
804 Eigen::Matrix<real_t, 6, 1>
a = Eigen::Matrix<real_t, 6, 1>::Zero(6);
805 A.svd().solve(b, &a);
815 Eigen::Matrix<real_t, 10, 10> A = Eigen::Matrix<real_t, 10, 10>::Zero(10,10);
816 Eigen::Matrix<real_t, 10, 1> b = Eigen::Matrix<real_t, 10, 1>::Zero(10);
818 real_t x0=_mesh->_coords[i*3], y0=_mesh->_coords[i*3+1], z0=_mesh->_coords[i*3+2];
819 assert(std::isfinite(x0));
820 assert(std::isfinite(y0));
821 assert(std::isfinite(z0));
823 for(
typename std::set<index_t>::const_iterator n=patch.begin(); n!=patch.end(); n++){
824 real_t x=_mesh->_coords[(*n)*3]-x0, y=_mesh->_coords[(*n)*3+1]-y0, z=_mesh->_coords[(*n)*3+2]-z0;
825 assert(std::isfinite(x));
826 assert(std::isfinite(y));
827 assert(std::isfinite(z));
828 assert(std::isfinite(psi[*n]));
831 A[10]+=x; A[11]+=x*x;
832 A[20]+=y; A[21]+=x*y; A[22]+=y*y;
833 A[30]+=z; A[31]+=x*z; A[32]+=y*z; A[33]+=z*z;
834 A[40]+=x*x; A[41]+=x*x*x; A[42]+=x*x*y; A[43]+=x*x*z; A[44]+=x*x*x*x;
835 A[50]+=x*y; A[51]+=x*x*y; A[52]+=x*y*y; A[53]+=x*y*z; A[54]+=x*x*x*y; A[55]+=x*x*y*y;
836 A[60]+=x*z; A[61]+=x*x*z; A[62]+=x*y*z; A[63]+=x*z*z; A[64]+=x*x*x*z; A[65]+=x*x*y*z; A[66]+=x*x*z*z;
837 A[70]+=y*y; A[71]+=x*y*y; A[72]+=y*y*y; A[73]+=y*y*z; A[74]+=x*x*y*y; A[75]+=x*y*y*y; A[76]+=x*y*y*z; A[77]+=y*y*y*y;
838 A[80]+=y*z; A[81]+=x*y*z; A[82]+=y*y*z; A[83]+=y*z*z; A[84]+=x*x*y*z; A[85]+=x*y*y*z; A[86]+=x*y*z*z; A[87]+=y*y*y*z; A[88]+=y*y*z*z;
839 A[90]+=z*z; A[91]+=x*z*z; A[92]+=y*z*z; A[93]+=z*z*z; A[94]+=x*x*z*z; A[95]+=x*y*z*z; A[96]+=x*z*z*z; A[97]+=y*y*z*z; A[98]+=y*z*z*z; A[99]+=z*z*z*z;
841 b[0]+=psi[*n]*1; b[1]+=psi[*n]*x; b[2]+=psi[*n]*y; b[3]+=psi[*n]*z; b[4]+=psi[*n]*x*x; b[5]+=psi[*n]*x*y; b[6]+=psi[*n]*x*z; b[7]+=psi[*n]*y*y; b[8]+=psi[*n]*y*z; b[9]+=psi[*n]*z*z;
844 A[1] = A[10]; A[2] = A[20]; A[3] = A[30]; A[4] = A[40]; A[5] = A[50]; A[6] = A[60]; A[7] = A[70]; A[8] = A[80]; A[9] = A[90];
845 A[12] = A[21]; A[13] = A[31]; A[14] = A[41]; A[15] = A[51]; A[16] = A[61]; A[17] = A[71]; A[18] = A[81]; A[19] = A[91];
846 A[23] = A[32]; A[24] = A[42]; A[25] = A[52]; A[26] = A[62]; A[27] = A[72]; A[28] = A[82]; A[29] = A[92];
847 A[34] = A[43]; A[35] = A[53]; A[36] = A[63]; A[37] = A[73]; A[38] = A[83]; A[39] = A[93];
848 A[45] = A[54]; A[46] = A[64]; A[47] = A[74]; A[48] = A[84]; A[49] = A[94];
849 A[56] = A[65]; A[57] = A[75]; A[58] = A[85]; A[59] = A[95];
850 A[67] = A[76]; A[68] = A[86]; A[69] = A[96];
851 A[78] = A[87]; A[79] = A[97];
854 Eigen::Matrix<real_t, 10, 1> a = Eigen::Matrix<real_t, 10, 1>::Zero(10);
855 A.svd().solve(b, &a);
857 Hessian[0] = a[4]*2.0;
860 Hessian[3] = a[7]*2.0;
862 Hessian[5] = a[9]*2.0;
868 int _NNodes, _NElements;
871 double min_eigenvalue;
void update_mesh()
Update the metric field on the mesh.
void set_metric_full(const real_t *metric)
void apply_min_edge_length(const real_t *min_len)
MetricField(Mesh< real_t > &mesh)
void fit_ellipsoid(int i, real_t *sm)
Calculates a number of element properties.
real_t predict_nelements_part()
void apply_max_edge_length(real_t max_len)
Constructs metric tensor field which encodes anisotropic edge size information.
void add_field(const real_t *psi, const real_t target_error, int p_norm=-1)
size_t get_number_elements() const
Return the number of elements in the mesh.
void apply_nelements(real_t nelements)
static void positive_definiteness(treal_t *metric)
real_t predict_nelements()
void relax_mesh(double omega)
Update the metric field on the mesh.
void get_metric(real_t *metric)
void get_metric(treal_t *metric)
void generate_mesh_metric(double resolution_scaling_factor)
void apply_min_edge_length(real_t min_len)
void set_metric(const real_t *metric)
void generate_Steiner_ellipse(double resolution_scaling_factor)
void set_metric(const treal_t *metric)
void generate_Steiner_ellipse(const double *x1, const double *x2, const double *x3, const double *x4, double *sm)
void apply_min_nelements(real_t nelements)
size_t get_number_nodes() const
Return the number of nodes in the mesh.
void apply_max_aspect_ratio(real_t max_aspect_ratio)
void apply_max_nelements(real_t nelements)
void constrain(const treal_t *M_in, bool perserved_small_edges=true)
void set_metric(const real_t *metric, int id)