Skip to content

Conversation

@danieldouglas92
Copy link
Contributor

Currently, faults and slabs dip from the surface at an angle orthogonal to the surface coordinates. In this PR, I want to add the ability for a user to specify an "obliquity vector" which tells the world builder what direction to dip the feature relative to the surface coordinates. An example of why this is useful can be seen in the images below:

The convergence of two plates on Earth is rarely perfectly orthogonal to the plate boundary, and in subduction zones there is varying degrees of oblique convergence of a plate relative to the plate margin. Currently, if a user wants to initialize a subducting plate that has undergone oblique convergence, the subducting plate will look like this:
image

The trench is rotated 45 degrees relative to the convergence direction, and so WorldBuilder by default also rotates the slab so that it remains orthogonal to the trench. If I specify an "obliquity vector" that is in the positive x-direction, then the slab looks like this:

image

which maintains the same convergence direction even with an oblique trench.

This is implemented by modifying the distance_point_from_curved_planes function in utilities.cc, and consists of two main chunks of code:

  1. Most of the time the current implementation will use a bezier_curve to find a point on the trench/fault that is closest to the check point. In this case, I use the check point and the obliquity_vector to create a line, which I then incrementally shift towards the bezier curve. If it intersects the bezier_curve, then this intersection point becomes the new "closest point" on the bezier_curve. If it doesn't converge, then the "closest point" is set to be a NAN.

  2. The bezier_curve misses points that are near the terminus of the surface coordinates. The way this is currently handled is definitely not generalized. It won't work for spherical and I don't think it will even work well for more complicated Cartesian geometries. I think this will require modifying the closest_point_on_curve_segment function in bezier_curve.cc. Right now, my idea is to check what the min/max values of the surface coordinates are, draw a line between the two extrema, and see if the check point (with the obliquity vector) will intersect this line. If it does, I check to see if the intersection point lies within the min/max values.

This is still very much a work in progress, I still need to add the "obliquity vector" as an input parameter that gets passed to distance_point_from_curved_planes, but I just wanted to open this PR so that I can get feedback on it!

@MFraters

@danieldouglas92
Copy link
Contributor Author

I've added an argument to distance_point_from_curved_planes that defines the direction of obliquity. I made the argument have a default value that was (DSNAN, DSNAN) so that all of the unit_tests should pass without modification. This works for simple linear trenches, but does not work for curved trenches yet.

image image image

Copy link
Member

@MFraters MFraters left a comment

Choose a reason for hiding this comment

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

Cool, nice minimal code change and well documented! A few initial comments and questions.

  1. I think the algorithm can maybe be simplified, which may help with the edges. I might be wrong, but I think you should use the closest point on the curve just as a guide. If it is not on the curve, use the endpoint which is closest to compute the distance. That would bet most of the code outside of the if (!std::isnan(closest_point_on_line_2d[0]) statement and should fix the corner cases in complex Cartesian and spherical cases. I haven't worked it out, so might be wrong ;)
  2. Can you show what happens in spherical?
  3. I think in the final version this parameter should become part of the sections. Do you agree? Just to note, that doesn't need to happen in this pull request, but we need to keep that in mind when making this.
  4. The slab seems to extend a bit beyond the plate, or is that just a visualization thing?

{
// We want to take the current checkpoint and move it along the obliquity vector using a parameterized line
// towards the bezier curve until we find a point on the bezier curve that intersects this parameterized line.
for (unsigned int i = 0; i < 100; ++i)
Copy link
Member

Choose a reason for hiding this comment

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

why 100? What if we don't converge before?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yea I don't really have a good reason for picking 100, I was torn between making the number of iterations an input parameter or not. I just chose 100 as a starting number, but if you think it should be higher/a user input parameter I would be ok with changing this.

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 should be a user defined value, since this is deep in the internals of the code. We need to make sure we always get a good solution within an acceptable tolerance.

I don't know what the right number is, but I think that is we do not converge, it should fail and not silently continue. This lets us (and the user) know that something went wrong, and that they get the wrong solution, so we can investigate it.

@danieldouglas92
Copy link
Contributor Author

@MFraters Thanks for taking a look at this so quickly! I addressed the comments on the code you left so far, and for the 4 points you outlined I'll work on addressing in the next couple days. Hopefully you are right that using the end of the bezier curve will work and simplify the code significantly.

For your points 2-4:

I actually haven't tried doing this in spherical, the current logic (in the loop outside of if (!std::isnan(closest_point_on_line_2d[0])) implicitly assumes a cartesian geometry since it just makes a straight line, whereas in spherical it would have to make an arc. If what you suggest works though, then what I have should work in spherical.

I do agree that this should become part of the sections, this would allow a lot more flexibility in the geometry of the slab along-strike.

I'm not sure what you mean by the slab seems to extend beyond the plate?

@MFraters
Copy link
Member

Great, thanks!

I'm not sure what you mean by the slab seems to extend beyond the plate?

image

@danieldouglas92
Copy link
Contributor Author

danieldouglas92 commented Nov 12, 2025

I changed the default value for the obliquity vector to be [inf, inf] (I was having issues with NANs). I also updated the flow of the code to first check to see if the point is near the edges of the Bezier curve. I'll work on testing this for curved trenches in Cartesian, and then start testing it in spherical geometries.

The slab extending beyond the plate is a visualization artifact!

@danieldouglas92
Copy link
Contributor Author

@MFraters

This seems to be working with a curved trench as well!

image image

I'll post what happens for spherical slabs soon

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.

2 participants