Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@domfournier
Copy link
Contributor

@domfournier domfournier commented Nov 8, 2023

Summary

The initial implementation of coterminal angles used an average of cell sizes to determine the cell centered length. Those distances are slightly different (by 88%) than the cell gradient distances used by the regularization_mesh.cell_gradient_ operators on octree changes.

PR Checklist

  • If this is a work in progress PR, set as a Draft PR
  • Linted my code according to the style guides.
  • Added tests to verify changes to the code.
  • [N/A] Added necessary documentation to any new functions/classes following the
    expect style.
  • Marked as ready for review (if this is was a draft PR), and converted
    to a Pull Request
  • Tagged @simpeg/simpeg-developers when ready for review.

What does this implement/fix?

Fixes large gradients computed on the -pi/pi transition, resulting in artifacts in the model.

Current results from examples\03-magnetics\plot_inv_mag_MVI_Sparse_TreeMesh.py.:

Title should be L2 Spherical model...

Figure_3

After fix:

Figure_3_new

@domfournier domfournier requested a review from jcapriot November 8, 2023 17:17
@codecov
Copy link

codecov bot commented Nov 8, 2023

Codecov Report

Attention: 1 lines in your changes are missing coverage. Please review.

Comparison is base (926fb1c) 82.30% compared to head (b66482a) 82.30%.

Files Patch % Lines
SimPEG/regularization/base.py 83.33% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1299      +/-   ##
==========================================
- Coverage   82.30%   82.30%   -0.01%     
==========================================
  Files         165      165              
  Lines       25244    25241       -3     
==========================================
- Hits        20778    20775       -3     
  Misses       4466     4466              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@domfournier domfournier requested a review from jcapriot November 8, 2023 18:17
@domfournier domfournier added this to the 0.21.0 milestone Nov 22, 2023
@domfournier domfournier assigned jcapriot and unassigned jcapriot Dec 6, 2023
Copy link
Member

@santisoler santisoler left a comment

Choose a reason for hiding this comment

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

Thanks @domfournier for this, and sorry leaving you waiting for this review.

I think this is ready to be merged. I just pushed a small change to improve the test function: now it runs the same test in the three orientations, not only on "y". I also renamed the function to be more descriptive.

Let me know what do you think. If you like it, ping me so I can merge this.

BTW, I just opened #1333 that it's related to this. If you can take a look at it, that would be great.

@domfournier
Copy link
Contributor Author

Thanks @domfournier for this, and sorry leaving you waiting for this review.

I think this is ready to be merged. I just pushed a small change to improve the test function: now it runs the same test in the three orientations, not only on "y". I also renamed the function to be more descriptive.

Let me know what do you think. If you like it, ping me so I can merge this.

BTW, I just opened #1333 that it's related to this. If you can take a look at it, that would be great.

Looks good man. I pushed a small fix to address your question on #1333 . Result looks good. Good to go on this end.


sub = theta[np.abs(theta) >= np.pi]
sub = -np.sign(sub) * (2 * np.pi - np.abs(sub))
sub = np.sign(sub) * (2 * np.pi - np.abs(sub))
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this will give you correct values now, simple testing:

>>> coterminal(np.pi + np.pi/4)
2.356194490192345  #3pi/4

it should give you -3pi/4.

I think the cleanest solution to this is to write the whole function as:

def coterminal(theta):
    return (theta + np.pi) % (2 * np.pi) - np.pi

Which will give you back a number on the domain of [-\pi, \pi)

Copy link
Member

Choose a reason for hiding this comment

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

I agree that using the mod is the cleanest way to solve this.

I would like to see that bugfix in another PR though. I think one of the reasons why this wasn't caught before was due to lack of tests, so besides the fix we should add more tests for it. And also update the docstrings for that function.

Copy link
Contributor Author

@domfournier domfournier Jan 20, 2024

Choose a reason for hiding this comment

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

And why would it be negative you think? That's what it was returning before.
I guess my initial implementation was to return the negative angle of the complement, thinking that if the gradient between two angles is large, we would want to force the model update to reduce both. But now I am not so sure if that logic works. We definitely get a different result with the example - just not convinced which one is best.

@domfournier
Copy link
Contributor Author

domfournier commented Jan 20, 2024

I get a line search failure with this @jcapriot

def coterminal(theta):
    return (theta + np.pi) % (2 * np.pi) - np.pi

I don't think that's quite it, since the modulo in python takes the sign of the dividor. For example

coterminal(-np.pi - np.pi/4) -> 3/4 np.pi

But would expect -pi/4

But this works

coterminal = np.sign(theta) * (np.abs(theta) % np.pi)

new

@jcapriot
Copy link
Member

I get a line search failure with this @jcapriot

def coterminal(theta):
    return (theta + np.pi) % (2 * np.pi) - np.pi

I don't think that's quite it, since the modulo in python takes the sign of the dividor. For example

coterminal(-np.pi - np.pi/4) -> 3/4 np.pi

But would expect -pi/4

But this works

coterminal = np.sign(theta) * (np.abs(theta) % np.pi)

new

$3\pi/4$ is the correct coterminal angle for $-\pi - \pi/4=-5\pi/4$

@jcapriot
Copy link
Member

Why did you put a negative in front there?:


coterminal = -((theta + np.pi) % (2 * np.pi) - np.pi)

instead of


coterminal = (theta + np.pi) % (2 * np.pi) - np.pi

@domfournier
Copy link
Contributor Author

Forget about the negative sign. I think we need to preserve the sign of the incoming angle.

We can argue all day about what the true coterminal should be mathematically, in the end we need the example in 03-magnetics/plot_inv_mag_MVI_Sparse_TreeMesh to return a smooth model, and not get weird stuff on the wrap around [-pi, pi]. That was the intent of this function.

Not this
image

@jcapriot
Copy link
Member

What layer are you cutting this at? Just so I can compare locally later this evening. I think I understand what you’re saying regarding what needs to happen during minimization. Just need to test a few things.

@jcapriot
Copy link
Member

Also probably the easiest way to “undo” the cell difference would be to just use dA = cell_gradient.sign() @ angles instead of dA= cell_distances * cell_gradient @ angles

@domfournier
Copy link
Contributor Author

I sliced it at the same index, but Z axis. Also adjusted the limits to [-75, 75] for close up.

@domfournier
Copy link
Contributor Author

Also probably the easiest way to “undo” the cell difference would be to just use dA = cell_gradient.sign() @ angles instead of dA= cell_distances * cell_gradient @ angles

Sounds good. Done.
I reverted the changes to coterminal as requested by @santisoler , to be addressed instead on PR #1334

@domfournier domfournier changed the title Fix issue with coterminal angle calculations Fix issue with lengthscales in coterminal angle calculations Jan 21, 2024
@jcapriot jcapriot closed this Jan 21, 2024
@jcapriot jcapriot reopened this Jan 21, 2024
@jcapriot
Copy link
Member

So these are the current results I'm getting on main:
image
image
These results mostly agree with what's on the current documentation page:
https://docs.simpeg.xyz/content/examples/03-magnetics/plot_inv_mag_MVI_Sparse_TreeMesh.html#sphx-glr-content-examples-03-magnetics-plot-inv-mag-mvi-sparse-treemesh-py

These are the results I'm getting with this PR:
image
image

@santisoler
Copy link
Member

santisoler commented Jan 22, 2024

Forget about the negative sign. I think we need to preserve the sign of the incoming angle.

We can argue all day about what the true coterminal should be mathematically, in the end we need the example in 03-magnetics/plot_inv_mag_MVI_Sparse_TreeMesh to return a smooth model, and not get weird stuff on the wrap around [-pi, pi]. That was the intent of this function.

I totally agree that the ultimate goal is to penalize non-smoothness in the neighboring angles in the model. That's also why I suggested of fixing the bug in coterminal in a separate PR: it's related to this one, but in the end they are different things.

I think the problem here is that we need to compute angles differences for each neighboring pair, and having a single array of coterminal angles moved to $[-\pi, \pi)$ (or any other interval of length of $2\pi$) won't solve it.

For example, if we have theta_1 = np.pi - 0.001 and theta_2 = -np.pi + 0.001, their difference is just 0.002, but if we compute the differences between their coterminal angles we'll get 2 * np.pi - 0.002, leading to an unwanted penalization for the smoothness of these two.

I think the solution is to have a function that can compute the difference between two angles that's smaller or equal than np.pi.

@jcapriot
Copy link
Member

Forget about the negative sign. I think we need to preserve the sign of the incoming angle.
We can argue all day about what the true coterminal should be mathematically, in the end we need the example in 03-magnetics/plot_inv_mag_MVI_Sparse_TreeMesh to return a smooth model, and not get weird stuff on the wrap around [-pi, pi]. That was the intent of this function.

I totally agree that the ultimate goal is to penalize non-smoothness in the neighboring angles in the model. That's also why I suggested of fixing the bug in coterminal in a separate PR: it's related to this one, but in the end they are different things.

I think the problem here is that we need to compute angles differences for each neighboring pair, and having a single array of coterminal angles moved to [−π,π) (or any other interval of length of 2π) won't solve it.

For example, if we have theta_1 = np.pi - 0.001 and theta_2 = -np.pi + 0.001, their difference is just 0.002, but if we compute the differences between their coterminal angles we'll get 2 * np.pi - 0.002, leading to an unwanted penalization for the smoothness of these two.

I think the solution is to have a function that can compute the difference between two angles that's smaller or equal than np.pi.

I think it's important to point out that we are already computing the coterminal angle after taking differences.

@jcapriot
Copy link
Member

In the meantime, this looks fine to me now, only issue is that the second order smoothness isn't being tested here (but it wasn't before either).

@domfournier
Copy link
Contributor Author

Ok so can we move this one forward, and battle it out further on #1334 ?

@domfournier domfournier reopened this Jan 22, 2024
@domfournier
Copy link
Contributor Author

So these are the current results I'm getting on main: image image These results mostly agree with what's on the current documentation page: https://docs.simpeg.xyz/content/examples/03-magnetics/plot_inv_mag_MVI_Sparse_TreeMesh.html#sphx-glr-content-examples-03-magnetics-plot-inv-mag-mvi-sparse-treemesh-py

The top plot is the smooth Cartesian result, no problem there. This what the smooth Spherical looks like on main

image

@jcapriot jcapriot merged commit b6cceab into main Jan 29, 2024
@jcapriot jcapriot deleted the Fix_coterminal_angles branch January 29, 2024 03:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants