Skip to content

PMP: Accelerate isotropic remeshing #5507

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Apr 6, 2021

Conversation

afabri
Copy link
Member

@afabri afabri commented Mar 2, 2021

Summary of Changes

vtuning in order to find small improvements to make.

Todo

  • Do tests with smaller than average edge length
  • Do test with larger than average edge length

Release Management

  • Affected package(s): Polygon_mesh_processing
  • License and copyright ownership: unchanged

@afabri afabri added the Pkg::PMP label Mar 2, 2021
@afabri afabri requested review from sloriot and janetournois March 2, 2021 14:01
@afabri
Copy link
Member Author

afabri commented Mar 2, 2021

I also replaced some std::vector with boost::container::small_vector (not committed) but it slowed things down.
When reading iphigenia.off I see std::getline() and CGAL::Euler::add_face() relatively high. That is not in isotropic remeshing, but let's mention it here.

@MaelRL MaelRL added the Speed label Mar 2, 2021
@MaelRL MaelRL added this to the 5.3-beta milestone Mar 2, 2021
@afabri
Copy link
Member Author

afabri commented Mar 2, 2021

@janetournois when I simplify (that is a target edge length larger than the average edge length) iphigenia.off, we spend 16% of the time in an exact collinearity test. Is that by accident or by construction?

I think there is a flaw. For the first hd the points t and q are the same vertex t.

image

@afabri
Copy link
Member Author

afabri commented Mar 2, 2021

@janetournois can we avoid this std::vector<std:vector<Vector_3>> ? For example just a vector per patch with one normal. And when the next normal of the same patch is computed, we do the test right away, and replace the one stored normal.

@@ -265,6 +264,7 @@ class Do_intersect_3
if (double_tmp_result < -eps)
return true;
else {
// return true; // AF: just to test conservative approach
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lrineau Maybe you have an idea for the following problem: We use this sphere/bbox test in the AABB tree for finding the closest triangle. While vtuning code I noticed that there are filter failures that is we do the test with exact arithmetic. I could well live with a true (that is overlap) in case of uncertainly. The question is, if we have to add such a functor to the kernel, or if we can add somehow a parameter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be a sort of "possibly intersect" instead of "do intersect".

CGAL::internal::Static_filters_predicates::Do_intersect_3 could have a third template parameter (a non-type template argument, I suggest a dedicated enum, to avoid the curve of a Boolean parameter), with a default-value.

Then we can add a new functor name in the Kernel concept, and it would be implemented using either Do_intersect_3 or CGAL::internal::Static_filters_predicates::Do_intersect_3 with the special value as third template argument.

I might actually be more efficient to implement that possibly_intersect(sphere, bbox) by do_overlap(sphere.bbox(), bbox).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that I also mentioned the tag this morning with #4654 in mind where we also brought the tag onto the table to allow/forbid degenerate input.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To use the bbox of the sphere makes it 25% slower.

@MaelRL MaelRL added the Not yet approved The feature or pull-request has not yet been approved. label Mar 4, 2021
@@ -1,6 +1,7 @@
#define EARLY
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be removed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer needed. It was for an #ifdef EARLY which I had in the code.

std::cout << "Read: " << t.time() << " sec" << std::endl;
t.reset();

double target_edge_length = (argc > 2) ? std::stod(std::string(argv[2])) : 1.0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to change the previous default?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By accident.

for(halfedge_descriptor h : halfedges(mesh_))
{
vertex_descriptor t = target(h, mesh_);
put(degree, t, get(degree,t)+1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@janetournois shall the degree depend only on the selected edges? This matters only for vertices on the boundary of a selection.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The degree of a vertex that stands on the boundary of the selection (i.e. on a PATCH_BORDER) should count only internal edges.
Here all edges are counted, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that in your code, IRC you were using degree() so Andreas' code does the same thing the original (to be checked)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But in the original code we call the degree() function for the vertex which does not distinguish either.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right.
valence(v) and target_valence(v) (which is 4 on borders and 6 elsewhere) both take into account only the "real" borders, not the patch borders.

It's not wrong, but maybe we can improve that, when a vertex stands at the limit between a patch to be remeshed and a patched to be left as is.
We can keep it this way for now.

@@ -859,6 +875,12 @@ namespace internal {
vvb -= 1;
vvc += 1;
vvd += 1;
#ifdef VALE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to keep that ? you observe no gain when activating it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact THAT is the code we must take.

@@ -1879,8 +1913,10 @@ namespace internal {
bool check_normals(const HalfedgeRange& hedges) const
{
std::size_t nb_patches = patch_id_to_index_map.size();
//std::vector<boost::optional<Vector_3> > normal_per_patch(nb_patches,boost::none);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I later replaced it with two vectors. By the way I am not sure if vector<bool> is a good idea, and if it should not be vector<int> instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would it be bad?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it is more time consuming to change a bit inside an int.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but you checked with optional and vector<bool> was faster? I agree with int since nb_patches is not expected to be very large

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not really see a difference in vtune but sticked to the second solution. I don''t agree on what you say on nb_patches. If it is the number of patches of the data set and not only the patches incident to the vertex it may be arbitrarily big.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is the total number of surface patches indeed, but still it's likely not to be arbitrarily big. A hundred would already be a strong data set...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it is more time consuming to change a bit inside an int.

That is very cheap, comparable to a memory load or a memory store from L1 cache. Both are about 3-4 CPU cycles. As soon as you have L1 caches misses, the memory load/stores are at more costly that that operation (setting a bit in a word).

That should be benched, but I doubt you will see any penalty for using std::vector<bool> instead of std::vector<int>

@janetournois
Copy link
Member

I made quite a few experiments with this branch, and all the results are good/similar to master.

About timings, the computation time (displayed by the demo) is on average 10 times faster than master on those experiments!

@afabri
Copy link
Member Author

afabri commented Mar 19, 2021

I have not planned to do more work on this. Note also that some improvements are not in the PMP package, so even other packages will profit from this PR.

@sloriot
Copy link
Member

sloriot commented Mar 19, 2021

I think the next step with this function should be #805. The improvement is very nice! Congrats.

@afabri
Copy link
Member Author

afabri commented Mar 19, 2021

I think the next step with this function should be #805. The improvement is very nice! Congrats.

But in an independent PR I would suggest, so that we have this one quickly in the master branch.

@sloriot
Copy link
Member

sloriot commented Mar 19, 2021

I think the next step with this function should be #805. The improvement is very nice! Congrats.

But in an independent PR I would suggest, so that we have this one quickly in the master branch.

Of course !

out.precision(17);
//out << mesh << std::endl;
out.close();

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MaelRL just spotted this. @janetournois shall we write a mesh or shall we just go back to the original file and also kick out the timer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it is the "main" example for isotropic remeshing, visible in the user manual, I would remove this and the timer too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you look at the other examples it seems that those who somehow modify the mesh or produce a mesh (union), at the end write the mesh to a file. We might unify. I also do not like the prefix or suffix example in the file names.

@MaelRL MaelRL requested a review from sloriot March 25, 2021 13:53
@MaelRL MaelRL removed the Not yet approved The feature or pull-request has not yet been approved. label Mar 25, 2021
@lrineau
Copy link
Member

lrineau commented Mar 29, 2021

@maxGimeno Both Sébastien and Mael approved this PR. It can be tested now.

sloriot added a commit to sloriot/cgal that referenced this pull request Apr 1, 2021
…g-GF

PMP:  Accelerate isotropic remeshing
@maxGimeno
Copy link
Contributor

@lrineau lrineau added rm only: ready for master For the release team only: that indicates that a PR is about to be merged in 'master' and removed Ready to be tested Under Testing labels Apr 6, 2021
@lrineau lrineau merged commit 58ddf16 into CGAL:master Apr 6, 2021
@lrineau lrineau removed the rm only: ready for master For the release team only: that indicates that a PR is about to be merged in 'master' label Apr 7, 2021
@lrineau lrineau deleted the PMP-vtune_isotropic_remeshing-GF branch April 7, 2021 07:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants