26 #include "../Rocblas/include/Rocblas.h"
27 #include "../Rocsurf/include/Generic_element_2.h"
28 #include "../Rocsurf/include/Rocsurf.h"
37 #define EXPORT_DEBUG_INFO 1
47 if ( feature_preserve) {
86 std::vector< COM::Pane*>::iterator it =
_panes.begin();
87 for (
int i=0, local_npanes =
_panes.size();
i<local_npanes; ++
i, ++it) {
88 COM::Pane *pane = *it;
89 if ( !pane->is_structured())
_is_strtd =
false;
94 _buf->get_communicator());
155 _buf->init_done(
false);
161 COM::Attribute *disps,
int *smoothed) {
164 "If no speed function, then time step must be zero.");
167 const COM::Attribute *spds_buf = spds ?
168 ( (spds->window() ==
_buf) ? spds :
169 _buf->inherit( const_cast<COM::Attribute*>(spds),
"speeds_inherited",
170 COM::Pane::INHERIT_USE,
true, NULL, 0)) : NULL;
171 COM::Attribute *disps_buf =
172 _buf->inherit( disps,
"disps_inherited", COM::Pane::INHERIT_USE,
174 COM::Attribute *disps_tmp =
175 _buf->inherit( disps,
"disps_inherited2", COM::Pane::INHERIT_CLONE,
177 _buf->init_done(
false);
180 SURF::Rocsurf::compute_element_areas(
_faceareas);
184 bool with_nodal_velo = dt>0 && spds->is_nodal() && spds->size_of_components()==3;
187 for (
int i=0; i<1+(_wf_expn && dt>0); ++
i) {
190 if ( with_nodal_velo)
220 bool needs_smoothing=(!smoothed || *smoothed);
221 if ( smoothed) *smoothed =
true;
223 if ( !needs_smoothing) {
225 if ( smoothed && *smoothed) *smoothed=
false;
239 if ( with_nodal_velo) {
248 _surf->reduce_on_shared_nodes( disps_buf, Manifold::OP_MAXABS);
251 #if EXPORT_DEBUG_INFO
252 COM::Attribute *ctypes = disps->window()->attribute(
"cnstr_types_nodal");
255 COM::Attribute *tranks = disps->window()->attribute(
"tangranks");
258 COM::Attribute *facenormals = disps->window()->attribute(
"facenormals");
261 COM::Attribute *facecenters = disps->window()->attribute(
"facecenters");
264 COM::Attribute *eigvecs = disps->window()->attribute(
"eigvecs");
267 COM::Attribute *lambdas = disps->window()->attribute(
"lambdas");
270 COM::Attribute *ridges = disps->window()->attribute(
"ridges");
272 disps->window()->inherit(
_ridges,
"ridges", COM::Pane::INHERIT_CLONE,
276 COM::Attribute *disps_novis = disps->window()->attribute(
"disps_novis");
288 if ( scale==1)
break;
291 std::cout <<
"Rocprop: Scaled back displacement with a factor of "
292 << scale << std::endl;
299 if ( smoothed) smoothed=
false;
306 #if EXPORT_DEBUG_INFO
308 COM::Attribute *scales = disps->window()->attribute(
"scales");
313 _surf->reduce_on_shared_nodes( disps_buf, Manifold::OP_MAXABS);
316 _buf->delete_attribute( disps_tmp->name());
317 _buf->delete_attribute( disps_buf->name());
318 if ( spds_buf && spds_buf!=spds)
319 _buf->delete_attribute( spds_buf->name());
320 _buf->init_done(
false);
343 SURF::Generic_element_2 e(ne);
350 "Speed must be scalar-elemental or 3-vector-nodal");
353 for (
int i=0;
i<ne; ++
i) pnts_buf[
i] = ps[
i];
356 if ( dt!=0 && ncomp==3) {
357 for (
int i=0;
i<ne; ++
i)
358 pnts_buf[
i] += disps[
i] = dt*((
const Vector_3*)spd_ptr)[ene[
i]-1];
361 for (
int i=0;
i<ne; ++
i) disps[
i] = null_vec;
370 e.Jacobian( pnts_buf, nc, J);
374 ns[0] = ns[1] = ns[2] = ns_nz;
377 for (
int k=0;
k<ne; ++
k) {
378 Vector_3 ts[] = { pnts_buf[(
k+1)%ne]-pnts_buf[
k],
379 pnts_buf[(k+ne-1)%ne]-pnts_buf[
k]};
383 double l = ns[
k].
norm();
384 if ( l >
std::abs(0.05*ts[0]*ts[1])) ns[
k] /= l;
390 if (dt!=0 && ncomp==1) {
391 double l = dt*spd_ptr[ene.
id()-1];
396 for (
int k=0;
k<ne; ++
k) pnts_buf[
k] += (disps[
k] = d);
399 for (
int k=0;
k<ne; ++
k) pnts_buf[
k] += (disps[
k] = l * ns[
k]);
405 for (
int i=0;
i<ne; ++
i) {
406 int vindex= ene[
i]-1;
408 if ( dirs[vindex].is_null()) {
410 pnts_buf[
i] = ps[
i] + disps[
i];
416 Vector_3 tng = ( pnts_buf[(
i+ne-1)%ne] - pnts_buf[
i]) +
417 (pnts_buf[(i+1)%ne] - pnts_buf[i]);
419 if ( tng * dir < 0) {
420 double l = (disps[
i] * ns[
i]);
421 if ( dir * ns[i]<0) l=-l;
423 (disps[
i] = dir) *= l;
425 pnts_buf[
i] = ps[
i] + disps[
i];
431 e.Jacobian( pnts_buf, nc, J);
435 ns[0] = ns[1] = ns[2] = ns_nz;
438 for (
int k=0;
k<ne; ++
k) {
440 ( pnts_buf[(
k+1)%ne]-pnts_buf[
k],
441 pnts_buf[(k+ne-1)%ne]-pnts_buf[k]).
normalize();
449 std::vector< COM::Pane*>::iterator it =
_panes.begin();
450 for (
int i=0, local_npanes =
_panes.size();
i<local_npanes; ++
i, ++it) {
451 COM::Pane *pane = *it;
455 ( pane->attribute(
_eigvecs->id())->pointer());
457 ( pane->attribute(
_eigvalues->id())->pointer());
459 ( pane->attribute(
_vnormals->id())->pointer());
461 ( pane->attribute(bo_attr->id())->pointer()) : NULL;
462 const char *trank = princ ?
reinterpret_cast<char*
>
463 ( pane->attribute(
_tangranks->id())->pointer()) : NULL;
466 for (
int j=0, jn=pane->size_of_real_nodes();
j<jn; ++
j) {
468 vnrms[j], voffset?voffset+j:NULL);
484 for (
int k=0;
k<nrank; ++
k) {
485 if ( lambdas[
k]>eps) {
486 d_offset += (es[
k]* *b_offset/-lambdas[
k])*es[
k];
490 *b_offset = d_offset;
495 for (
int k=0;
k<nrank; ++
k) {
496 if ( lambdas[
k]>eps) {
497 d_medial += (es[
k] * b_medial/-lambdas[
k])*es[
k];
507 COM::Attribute *vcenters) {
510 std::vector< COM::Pane*>::iterator it =
_panes.begin();
511 Manifold::PM_iterator pm_it=
_surf->pm_begin();
516 for (
int i=0, local_npanes =
_panes.size();
i<local_npanes; ++
i, ++it) {
517 COM::Pane *pane = *it;
521 ( pane->attribute(
_eigvecs->id())->pointer());
523 ( pane->attribute(
_eigvalues->id())->pointer());
525 ( pane->attribute(disps_buf->id())->pointer()) : NULL;
527 ( pane->attribute(
_boffset->id())->pointer());
529 ( pane->attribute(
_bmedial->id())->pointer());
532 const char *tranks =
reinterpret_cast<char*
>
533 ( pane->attribute(
_tangranks->id())->pointer());
535 ( pane->attribute(vcenters->id())->pointer()) : NULL;
536 const char *val_bndry_nodes =
reinterpret_cast<const char*
>
540 ( pane->attribute(
_As->id())->pointer());
541 const int *cnstrs =
_cnstr_nodes ?
reinterpret_cast<int*
>
542 ( pane->attribute(
_cnstr_nodes->id())->pointer()) : NULL;
545 for (
int j=0, jn=pane->size_of_real_nodes();
j<jn; ++
j) {
548 if ( lambdas[
j][0]==0)
continue;
551 int nrank = 3-tranks[
j];
558 lambdas[
j] = es_v[0] = es_v[1] = es_v[2] = null_vec;
560 if (ds) ds[
j] = null_vec;
561 if (vcnts) vcnts[
j] = null_vec;
568 double cos_fangle = 0.98481, sin_fangle = 0.17365;
572 for (
int k=0;
k<nrank; ++
k) {
573 if ( lambdas[j][
k]>eps)
574 b += ds[
j]*es_v[
k]*es_v[
k];
581 for (
int k=1;
k<3; ++
k) {
582 if (
k>=nrank || lambdas[j][
k]<eps)
584 t += vcnts[
j]*es_v[
k]*es_v[
k];
588 if ( ndirs == 0)
continue;
592 if ( ds && ds[j]!=null_vec) {
596 if ( ds) ds[
j] = null_vec;
608 if ( det < cos_fangle || val_bndry_nodes[j]) {
610 V[0] = nrm_v; V[0] -= V[0]*nrm*nrm; V[0].
normalize();
613 if (vcnts) vcnts[
j] = vcnts[
j]*V[1]*V[1];
616 vcnts[
j] -= vcnts[
j]*nrm*nrm;
618 if ( ds) ds[
j] = null_vec;
622 else if ( vcnts && !val_bndry_nodes[j] &&
623 ( tranks[j]==1 &&
std::abs(V[0]*es_v[2]) > cos_fangle ||
624 tranks[j]==2 &&
std::abs(V[0]*nrm_v) < sin_fangle)) {
626 vcnts[
j] = vcnts[
j]*V[0]*V[0];
627 if ( ds) ds[
j] = null_vec;
631 if ( ds && !ds[j].is_null()) {
632 double VAV=
Vector_3(V[0]*A_v[0],V[0]*A_v[1],V[0]*A_v[2])*V[0];
633 double Vb = V[0]*bs[
j];
638 ds[
j] = (-Vb/VAV)*V[0];
639 if ( ndirs==1 && vcnts) vcnts[
j] = null_vec;
655 COM::Attribute *vcenters,
int depth) {
657 double alpha = HUGE_VAL;
660 std::vector< COM::Pane*>::iterator it =
_panes.begin();
661 Manifold::PM_iterator pm_it=
_surf->pm_begin();
662 for (
int i=0, local_npanes =
_panes.size();
i<local_npanes;
663 ++
i, ++it, ++pm_it) {
664 COM::Pane *pane = *it;
667 (pane->attribute(
COM_NC)->pointer());
669 ( pane->attribute(disps->id())->pointer());
671 ( pane->attribute(vcenters->id())->pointer());
674 const char *tranks =
reinterpret_cast<char*
>
675 ( pane->attribute(
_tangranks->id())->pointer());
680 for (
int j=0,
nj=pane->size_of_real_elements();
j<
nj; ++
j, ene.
next()) {
682 int uindex=ene[ne-1]-1, vindex=ene[0]-1, windex=0;
685 for (
int k=0;
k<ne; ++
k, uindex=vindex, vindex=windex ) {
686 windex = ene[(
k+1==ne)?0:k+1]-1;
688 if ( k!=0 && ne!=4 && (tranks[uindex] == 2 || tranks[vindex] == 2))
691 Vector_3 tngs[2] = { pnts[uindex]-pnts[vindex],
692 pnts[windex]-pnts[vindex]};
694 Vector_3 disp_v = ds[vindex]+vcnts[vindex];
695 Vector_3 dsps[2] = { ds[uindex]+vcnts[uindex]-disp_v,
696 ds[windex]+vcnts[windex]-disp_v };
708 if ( roots.first<alpha && roots.first>0) alpha = roots.first;
709 if ( roots.second<alpha && roots.second>0) alpha = roots.second;
712 Edge_ID eid(
j+1,k), eid_opp = pm_it->get_opposite_real_edge( eid);
713 bool is_border_edge = pm_it->is_physical_border_edge( eid_opp);
715 if ( tranks[uindex] != 2 && tranks[vindex] != 2 && !is_border_edge) {
717 const Vector_3 &n2 = eid_opp.is_border() ?
718 pm_it->get_bd_normal( eid_opp) : fnrms[eid_opp.eid()-1];
726 if ( roots.first<alpha && roots.first>0) alpha = roots.first;
727 if ( roots.second<alpha && roots.second>0) alpha = roots.second;
734 MPI_Comm comm =
_buf->get_communicator();
735 int needs_rescale = alpha*
_courant<=1;
738 double local = alpha;
739 MPI_Allreduce(&local, &alpha, 1, MPI_DOUBLE,
MPI_MIN, comm);
741 int local_nr = needs_rescale;
742 MPI_Allreduce( &local_nr, &needs_rescale, 1, MPI_INT,
MPI_LOR, comm);
746 if ( _courant>0 && alpha*_courant<=1) {
747 double scale = 0.9*_courant*alpha;
752 const int maxdepth=6;
753 if ( depth>maxdepth) {
754 std::cerr <<
"Rocprop: Mesh too distorted. Stopping" << std::endl;
771 std::pair<double,double>
776 { a /= max_abc; b /= max_abc; c /= max_abc; }
780 return std::make_pair(HUGE_VAL, HUGE_VAL);
783 return std::make_pair(-c/b, HUGE_VAL);
786 double det = b*b - 4*a*c;
788 return std::make_pair(HUGE_VAL, HUGE_VAL);
794 double temp = -b - sqrt_d;
795 return std::make_pair(2*c/temp, 0.5*temp/a);
798 double temp = -b + sqrt_d;
799 return std::make_pair( 0.5*temp/a, 2*c/temp);
COM::Attribute * _ridgeneighbors
COM::Attribute * _eigvalues
An adaptor for enumerating node IDs of an element.
#define PROP_END_NAMESPACE
virtual double time_stepping(const COM::Attribute *spds, double dt, COM::Attribute *disps, int *smoothed=NULL)
Main entry of the algorithm.
An Attribute object is a data member of a window.
COM::Attribute * _cnstr_nodes
void obtain_face_offset(const Point_3 *pnts, const double *spd_ptr, const COM::Attribute *spd, double dt, const Vector_3 *dirs, COM::Element_node_enumerator &ene, Vector_3 &ns_nz, Point_3 &cnt, Vector_3 *disps, Vector_3 *ns)
void filter_and_identify_ridge_edges(bool filter_curves)
Filter out isolated ridge vertices and identify ridge edges.
bool obtain_constrained_directions(COM::Attribute *disps, COM::Attribute *vcenters)
Decompose propagation directions based on constraints.
#define PROP_BEGIN_NAMESPACE
#define COM_assertion_msg(EX, msg)
Vector_n max(const Array_n_const &v1, const Array_n_const &v2)
COM::Attribute * _vcenters
COM::Attribute * _faceareas
COM::Attribute * _boffset
here we put it at the!beginning of the common block The point to point and collective!routines know about but MPI_TYPE_STRUCT as yet does not!MPI_STATUS_IGNORE and MPI_STATUSES_IGNORE are similar objects!Until the underlying MPI library implements the C version of these are declared as arrays of MPI_STATUS_SIZE!The types and are OPTIONAL!Their values are zero if they are not available Note that!using these reduces the portability of MPI_IO INTEGER MPI_BOTTOM INTEGER MPI_DOUBLE_PRECISION INTEGER MPI_LOGICAL INTEGER MPI_2REAL INTEGER MPI_2DOUBLE_COMPLEX INTEGER MPI_LB INTEGER MPI_WTIME_IS_GLOBAL INTEGER MPI_GROUP_EMPTY INTEGER MPI_MIN
void update_vertex_centers()
void compute_directions(COM::Attribute *b_offset, bool in_principle)
Compute mean normals.
SURF::Vector_3< Real > Vector_3
COM::Attribute * _tangranks
CImg< _cimg_Tfloat > tan(const CImg< T > &instance)
int id() const
Get the local id of the element within the pane.
std::pair< double, double > solve_quadratic_func(double a, double b, double c)
void denoise_surface(const COM::Attribute *disps_buf, COM::Attribute *normal_motion)
int COMMPI_Comm_size(MPI_Comm c)
std::vector< COM::Pane * > _panes
COM::Attribute * _eigvecs
static double square(double x)
virtual void bound_nodal_motion(COM::Attribute *disps)
This is a helper class for accessing nodal data.
COM::Attribute * _facecenters
static void add(const Attribute *x, const Attribute *y, Attribute *z)
Operation wrapper for addition.
SURF::Window_manifold_2 Manifold
static void mul_scalar(const Attribute *x, const void *y, Attribute *z, int swap=0)
Operation wrapper for multiplication with y as a scalar pointer.
int size_of_edges() const
Number of edges per element.
void compute_quadrics(double dt, const COM::Attribute *spds, COM::Attribute *rhs, COM::Attribute *predicted)
Compute quadrics for every vertex.
void reset_default_parameters(bool b=false)
COM::Attribute * _bmedial
COM::Attribute * _weights
static Vector_3 cross_product(const Vector_3 &v, const Vector_3 &w)
void obtain_directions(Vector_3 es[3], const Vector_3 &lambdas, int nrank, Vector_3 &b_medial, Vector_3 *b_offset=NULL) const
void compute_anisotropic_vertex_centers(const COM::Attribute *disps_buf)
bool is_nodal() const
Checks whether the attribute is associated with a node.
here we put it at the!beginning of the common block The point to point and collective!routines know about but MPI_TYPE_STRUCT as yet does not!MPI_STATUS_IGNORE and MPI_STATUSES_IGNORE are similar objects!Until the underlying MPI library implements the C version of these are declared as arrays of MPI_STATUS_SIZE!The types and are OPTIONAL!Their values are zero if they are not available Note that!using these reduces the portability of MPI_IO INTEGER MPI_BOTTOM INTEGER MPI_DOUBLE_PRECISION INTEGER MPI_LOGICAL INTEGER MPI_2REAL INTEGER MPI_2DOUBLE_COMPLEX INTEGER MPI_LB INTEGER MPI_WTIME_IS_GLOBAL INTEGER MPI_GROUP_EMPTY INTEGER MPI_BAND INTEGER MPI_LOR
double det(const Matrix3D &A)
static void copy_scalar(const void *x, Attribute *y)
Operation wrapper for copy (x is a scalar pointer).
void mark_weak_vertices()
Mark vertices that are weak.
double rescale_displacements(COM::Attribute *disps, COM::Attribute *vcenters, int depth=0)
Reduce time step based on stability limit, and rescale displacements by the reduced time step and dif...
COM::Attribute * _cnstr_bndry_nodes
void set(const Value *p, Element_node_enumerator &ene, int strd)
initialize the accessor with a pointer and a specific stride.
static void copy(const Attribute *x, Attribute *y)
Wrapper for copy.
COM::Attribute * _vnormals
static void get_constraint_directions(int type, int &ndirs, Vector_3 dirs[2])
Get orthonormals of the constraints.
void next()
Go to the next element within the connectivity tables of a pane.
Some basic geometric data types.
This class provides some common primitives used by various propagation algorithms.
void nulaplacian_smooth(const COM::Attribute *vert_normals, const COM::Attribute *tangranks, const COM::Attribute *disps, COM::Attribute *vcenters, COM::Attribute *buf, COM::Attribute *vert_weights_buf, const COM::Attribute *edge_weights=NULL)
Redistribute smooth vertices by NuLaplacian smoothing.
FaceOffset_3()
Default constructor.
bool is_elemental() const
Checks whether the attribute is associated with an element.
COM::Attribute * _facenormals
COM::Attribute * _ctangranks
int size_of_components() const
Obtain the number of components in the attribute.