Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/world_builder/features/subducting_plate.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ namespace WorldBuilder
*/
Point<2> reference_point;

/**
* A vector on the surface that indicates the direction of convergence
* of the subducting plate relative to the trench.
*/
// Point<2> obliquity_vector;
std::vector<double> obliquity_vector;

std::vector<std::vector<double> > slab_segment_lengths;
std::vector<std::vector<Point<2> > > slab_segment_thickness;
std::vector<std::vector<Point<2> > > slab_segment_top_truncation;
Expand Down
3 changes: 2 additions & 1 deletion include/world_builder/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,8 @@ namespace WorldBuilder
const double start_radius,
const std::unique_ptr<CoordinateSystems::Interface> &coordinate_system,
const bool only_positive,
const Objects::BezierCurve &bezier_curve);
const Objects::BezierCurve &bezier_curve,
std::vector<double> obliquity_vector = {std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()});



Expand Down
14 changes: 11 additions & 3 deletions source/world_builder/features/subducting_plate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ namespace WorldBuilder
"The depth to which this feature is present");
prm.declare_entry("dip point", Types::Point<2>(),
"The depth to which this feature is present");

prm.declare_entry("obliquity vector", Types::Array(Types::Double(std::numeric_limits<double>::infinity()),2),
"A vector on the surface that indicates the direction of convergence of the subducting plate relative to the trench.");
/*prm.declare_entry("segments", Types::Array(Types::Segment(0,Point<2>(0,0,invalid),Point<2>(0,0,invalid),Point<2>(0,0,invalid),
Types::PluginSystem("", Features::SubductingPlateModels::Temperature::Interface::declare_entries, {"model"}),
Types::PluginSystem("", Features::SubductingPlateModels::Composition::Interface::declare_entries, {"model"}),
Expand Down Expand Up @@ -172,12 +173,17 @@ namespace WorldBuilder

reference_point = prm.get<Point<2> >("dip point");

obliquity_vector = prm.get_vector<double>("obliquity vector");

if (coordinate_system == spherical)
{
// When spherical, input is in degrees, so change to radians for internal use.
reference_point *= (Consts::PI/180.);
for (double &value : obliquity_vector)
value *= (Consts::PI/180.);
}


default_temperature_models.resize(0);
default_composition_models.resize(0);
default_grains_models.resize(0);
Expand Down Expand Up @@ -540,7 +546,8 @@ namespace WorldBuilder
starting_radius,
this->world->parameters.coordinate_system,
false,
this->bezier_curve);
this->bezier_curve,
obliquity_vector);

const double distance_from_plane = distance_from_planes.distance_from_plane;
const double distance_along_plane = distance_from_planes.distance_along_plane;
Expand Down Expand Up @@ -839,7 +846,8 @@ namespace WorldBuilder
starting_radius,
this->world->parameters.coordinate_system,
false,
this->bezier_curve);
this->bezier_curve,
obliquity_vector);

Objects::PlaneDistances plane_distances(distance_from_planes.distance_from_plane, distance_from_planes.distance_along_plane);
return plane_distances;
Expand Down
157 changes: 154 additions & 3 deletions source/world_builder/utilities.cc
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,8 @@ namespace WorldBuilder
const double start_radius,
const std::unique_ptr<CoordinateSystems::Interface> &coordinate_system,
const bool only_positive,
const Objects::BezierCurve &bezier_curve)
const Objects::BezierCurve &bezier_curve,
std::vector<double> obliquity_vector)
{
// Initialize variables that this function will return
double distance = std::numeric_limits<double>::infinity();
Expand Down Expand Up @@ -427,9 +428,159 @@ namespace WorldBuilder
double fraction_CPL_P1P2 = std::numeric_limits<double>::infinity();

// Get the closest point on the curve (the trench or the fault trace) to the check point.
const Objects::ClosestPointOnCurve closest_point_on_curve = bezier_curve.closest_point_on_curve_segment(check_point_surface_2d);
Objects::ClosestPointOnCurve closest_point_on_curve = bezier_curve.closest_point_on_curve_segment(check_point_surface_2d);
Point<2> closest_point_on_line_2d = closest_point_on_curve.point;

// If the obliquity_vector is not infinite, this means that the user has specified an obliquity vector.
// This will require a potential modification of the `closest_point_on_line_2d` variable. We will take
// the check point and use it with the obliquity vector to parameterize a line and see where this line
// intersects the Bezier curve. If it does intersect the Bezier curve, then this intersection point will
// become the new `closest_point_on_line_2d`, otherwise it will be set to NaN.
// if (obliquity_vector_point.norm() > std::numeric_limits<double>::min())
if (std::isfinite(obliquity_vector[0]))
{
Point<2> obliquity_vector_point(obliquity_vector[0], obliquity_vector[1], natural_coordinate_system);
// Normalize the vector
obliquity_vector_point = obliquity_vector_point / obliquity_vector_point.norm();

// If the check point is near the ends of the Bezier curve, there is a chance that the Bezier curve will not
// find a closest point. Check for this case by seeing if the line created by the checkpoint and the obliquity
// vector intersects the end segments of the Bezier curve.
Point<2> iterable_check_point_surface_2d = check_point_surface_2d;
Objects::ClosestPointOnCurve iterable_closest_point_on_curve = bezier_curve.closest_point_on_curve_segment(iterable_check_point_surface_2d);

if (std::isnan(closest_point_on_line_2d[0]))
{
const Point<2> p1 = point_list[0];
const Point<2> p2 = point_list[point_list.size()-1];
const double dist_p1 = check_point_surface_2d.distance(p1);
const double dist_p2 = check_point_surface_2d.distance(p2);
const Point<2> closest_terminal_point = dist_p1 < dist_p2 ? p1 : p2;
double closest_distance_to_trench = dist_p1 < dist_p2 ? dist_p1 : dist_p2;

const Point<2> second_closest_terminal_point = dist_p1 < dist_p2 ? point_list[1] : point_list[point_list.size()-2];
for (unsigned int i = 0; i < 100; ++i)
{
const Point<2> vector_closest_point_to_checkpoint = closest_terminal_point - iterable_check_point_surface_2d;
const double line_factor = obliquity_vector_point * vector_closest_point_to_checkpoint < 0 ? -1.0 : 1.0;

// Parameterize a line through the checkpoint along the obliquity vector.
Point<2> parameterized_line(iterable_check_point_surface_2d[0] + line_factor * closest_distance_to_trench * obliquity_vector_point[0],
iterable_check_point_surface_2d[1] + line_factor * closest_distance_to_trench * obliquity_vector_point[1],
natural_coordinate_system);
const double new_distance1 = parameterized_line.distance(closest_terminal_point);
const double new_distance2 = parameterized_line.distance(second_closest_terminal_point);
const double new_distance_search = std::min(new_distance1, new_distance2);

if (new_distance_search < closest_distance_to_trench)
{
// We are getting closer to the trench, so continue the search.
iterable_check_point_surface_2d = parameterized_line;
closest_distance_to_trench = new_distance_search;

if (!std::isnan(bezier_curve.closest_point_on_curve_segment(iterable_check_point_surface_2d).point[0]))
{
closest_point_on_curve = bezier_curve.closest_point_on_curve_segment(iterable_check_point_surface_2d);
closest_point_on_line_2d = bezier_curve.closest_point_on_curve_segment(iterable_check_point_surface_2d).point;
iterable_closest_point_on_curve = closest_point_on_curve;
break;
}

}
}
}
// Check if the bezier_curve has found a point on the curve that is closest to the checkpoint (without considering the obliquity vector).
// If so, we need to check whether this point is on the correct side of the curve, given the reference point.
// If the bezier_curve has not found a point on the curve that is closest to the checkpoint, check to see if the point will still
// intersect the trench given the obliquity_vector.
if (!std::isnan(closest_point_on_line_2d[0]))
{
Point<2> check_point_surface_2d_temp_ob = iterable_check_point_surface_2d;

if (!bool_cartesian)
{
const double normal = std::fabs(point_list[i_section_min_distance+static_cast<size_t>(std::round(fraction_CPL_P1P2))][0]-check_point_surface_2d[0]);
const double plus = std::fabs(point_list[i_section_min_distance+static_cast<size_t>(std::round(fraction_CPL_P1P2))][0]-(check_point_surface_2d[0]+2*Consts::PI));
const double min = std::fabs(point_list[i_section_min_distance+static_cast<size_t>(std::round(fraction_CPL_P1P2))][0]-(check_point_surface_2d[0]-2*Consts::PI));

// find out whether the check point, checkpoint + 2pi or check point -2 pi is closest to the point list.
if (plus < normal)
{
check_point_surface_2d_temp_ob[0]+= 2*Consts::PI;
}
else if (min < normal)
{
check_point_surface_2d_temp_ob[0]-= 2*Consts::PI;
}
}

const Point<2> AB_normal_ob = closest_point_on_curve.normal*closest_point_on_line_2d.distance(reference_point);//*AB.norm();
const Point<2> local_reference_point_ob = AB_normal_ob + closest_point_on_line_2d;
const bool reference_normal_on_side_of_line_ob = (closest_point_on_line_2d-local_reference_point_ob).norm_square() < (check_point_surface_2d_temp_ob-local_reference_point_ob).norm_square();
const bool reference_point_on_side_of_line_ob = (point_list[point_list.size()-1][0] - point_list[0][0])*(reference_point[1] - point_list[0][1]) - (reference_point[0] - point_list[0][0])*(point_list[point_list.size()-1][1] - point_list[0][1]) < 0.;

double old_dist;
double new_dist;
bool converged = false;

if (reference_normal_on_side_of_line_ob != reference_point_on_side_of_line_ob)
{
// 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.

{
// We will use the distance of the check point to the current "closest point on curve" to scale the distance
// traveled along the parameterized line.
old_dist = iterable_closest_point_on_curve.distance / 1.1;

// If the sign of the dot product of the obliquity vector and the vector connecting the closest point on
// the curve to the check point is positive, then we want to move along the obliquity vector in the negative direction,
// otherwise in the positive direction.
const Point<2> vector_closest_point_to_checkpoint = iterable_check_point_surface_2d - iterable_closest_point_on_curve.point;
const double line_factor = obliquity_vector_point * vector_closest_point_to_checkpoint < 0 ? -1.0 : 1.0;

// Parameterize a line through the checkpoint along the obliquity vector.
Point<2> parameterized_line(iterable_check_point_surface_2d[0] + line_factor * old_dist * obliquity_vector_point[0],
iterable_check_point_surface_2d[1] + line_factor * old_dist * obliquity_vector_point[1],
natural_coordinate_system);

// Check where the closest point on the Bezier curve is relative to the new check point (after moving along the
// obliquity vector).
iterable_closest_point_on_curve = bezier_curve.closest_point_on_curve_segment(parameterized_line);
iterable_check_point_surface_2d = parameterized_line;

// The new distance from the bezier curve. Use this to check to see if we are converging/have converged.
new_dist = iterable_closest_point_on_curve.distance;

// If the distance is increasing, this means that we are moving away from the trench, so abort the search
// and return NAN's for the closest point to ensure this point doesn't get used.
// NOTE: I think this makes sense most of the time, for example if the obliquity vector is parallel to the
// bezier curve, you will never get closer to it. But I'm not sure this is fully general.
if (std::abs(old_dist - new_dist) >= std::abs(old_dist))
{
closest_point_on_line_2d[0] = NaN::DQNAN;
closest_point_on_line_2d[1] = NaN::DQNAN;
break;
}

// The new distance and the old distance are very close, implying the point has converged.
if (std::abs(new_dist - old_dist) < 1)
{
converged = true;
break;
}
}
}

// If converged, update the closest point to the intersection of the obliquity vector with the bezier curve.
if (converged)
{
closest_point_on_curve = bezier_curve.closest_point_on_curve_segment(iterable_check_point_surface_2d);
closest_point_on_line_2d = closest_point_on_curve.point;
}
}
}

// We now need 3d points from this point on, so make them.
// The order of a Cartesian coordinate is x,y,z and the order of
// a spherical coordinate it radius, long, lat (in rad).
Expand Down Expand Up @@ -638,7 +789,7 @@ namespace WorldBuilder

// check whether the check point and the reference point are on the same side, if not, change the side.
const Point<2> AB_normal = closest_point_on_curve.normal*closest_point_on_line_2d.distance(reference_point);//*AB.norm();
const Point<2> local_reference_point = AB_normal*1.+closest_point_on_line_2d;
const Point<2> local_reference_point = AB_normal + closest_point_on_line_2d;
const bool reference_normal_on_side_of_line = (closest_point_on_line_2d-local_reference_point).norm_square() < (check_point_surface_2d_temp-local_reference_point).norm_square();
const bool reference_point_on_side_of_line = (point_list[point_list.size()-1][0] - point_list[0][0])*(reference_point[1] - point_list[0][1]) - (reference_point[0] - point_list[0][0])*(point_list[point_list.size()-1][1] - point_list[0][1]) < 0.;
const double reference_on_side_of_line = reference_normal_on_side_of_line == reference_point_on_side_of_line ? 1 : -1;
Expand Down
11 changes: 11 additions & 0 deletions tests/gwb-dat/linear_cartesian_obliquity.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This is a comment in the data
# file.
# Now define parameters:
# dim = 3
# compositions = 0
# x y z d T C0
3000e3 510e3 0e3 20e3
3050e3 510e3 0e3 30e3
3100e3 510e3 0e3 50e3
3150e3 510e3 0e3 90e3
3200e3 510e3 0e3 150e3
Loading
Loading