diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dd1b7aef..971fc9ec8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Added a cmake target to update the reference test results called `update_test_references`. \[Menno Fraters; 2022-04-12; [#404](github.com/GeodynamicWorldBuilder/WorldBuilder/issues/404)\] - Added a new multi property query interface called properties to the world. This allows to ask for different properties at the same time, which significantly improve performance. Internally all other interface now use this properties function to reduce complexity. \[Menno Fraters; 2022-04-18; [#409](github.com/GeodynamicWorldBuilder/WorldBuilder/issues/409) and [#410](github.com/GeodynamicWorldBuilder/WorldBuilder/issues/410)\] - Added a new compositional model for fault models such that ensures a smooth transition of compositional value from the fault trace until a particular user-determined distance. This feature can be helpful for model that uses composition of fault to compute other material properties, e.g., viscosity. \[Arushi Saxena; 2022-05-19; [#356](https://github.com/GeodynamicWorldBuilder/WorldBuilder/pull/356) +- Added an interface to compute the distance of a query point to a feature's plane. For example, the distance of a point to a subducting slab could be duely computed. This interface simply calls the previously implemented interfaces of the feature objects and wrap them up. Thus it only takes variables like coordinates and depth in the model and could be called from ASPECT directly. +\[Haoyuan Li; 2022-12-23; [#453](https://github.com/GeodynamicWorldBuilder/WorldBuilder/pull/453) ### Changed - The World Builder Visualizer will now use zlib compression for vtu files by default. If zlib is not available binary output will be used. \[Menno Fraters; 2021-06-26; [#282](github.com/GeodynamicWorldBuilder/WorldBuilder/pull/282)\] diff --git a/include/world_builder/features/interface.h b/include/world_builder/features/interface.h index 22e58ce96..c656aa6cf 100644 --- a/include/world_builder/features/interface.h +++ b/include/world_builder/features/interface.h @@ -23,6 +23,7 @@ #include "world_builder/grains.h" #include "world_builder/utilities.h" +#include "world_builder/objects/distance_from_surface.h" namespace WorldBuilder { @@ -107,6 +108,17 @@ namespace WorldBuilder */ static std::unique_ptr create(const std::string &name, WorldBuilder::World *world); + /** + * Returns a PlaneDistances object that has the distance from and along a feature plane, + * caculated from the coordinates and the depth of the point. + */ + virtual + Objects::PlaneDistances + distance_to_feature_plane(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth) const; + + protected: /** * A pointer to the world class to retrieve variables. diff --git a/include/world_builder/features/subducting_plate.h b/include/world_builder/features/subducting_plate.h index 212d1ac85..2e7b02460 100644 --- a/include/world_builder/features/subducting_plate.h +++ b/include/world_builder/features/subducting_plate.h @@ -26,6 +26,7 @@ #include "world_builder/features/subducting_plate_models/temperature/interface.h" #include "world_builder/types/segment.h" #include "world_builder/bounding_box.h" +#include "world_builder/objects/distance_from_surface.h" namespace WorldBuilder @@ -129,6 +130,16 @@ namespace WorldBuilder const std::vector &entry_in_output, std::vector &output) const override final; + /** + * Returns a PlaneDistances object that has the distance from and along a subducting plate plane, + * caculated from the coordinates and the depth of the point. + */ + Objects::PlaneDistances + distance_to_feature_plane(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth) const override; + + private: std::vector > default_temperature_models; std::vector > default_composition_models; diff --git a/include/world_builder/objects/distance_from_surface.h b/include/world_builder/objects/distance_from_surface.h new file mode 100644 index 000000000..dc3c818c7 --- /dev/null +++ b/include/world_builder/objects/distance_from_surface.h @@ -0,0 +1,64 @@ +/* +Copyright (C) 2018 - 2022 by the authors of the World Builder code. + +This file is part of the World Builder. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef WORLD_BUILDER_OBJECTSS_DISTANCE_FROM_SURFACE_H +#define WORLD_BUILDER_OBJECTSS_DISTANCE_FROM_SURFACE_H + +namespace WorldBuilder +{ + namespace Objects + { + class PlaneDistances + { + public: + + /** + * Constructor to create an PlaneDistances object from the distance + * from and along the surface of plane + */ + PlaneDistances(const double distance_from_surface_, const double distance_along_surface_) + : + distance_from_surface(distance_from_surface_), + distance_along_surface(distance_along_surface_) + {} + + /** + * Function to get the distance from the surface + */ + double get_distance_from_surface(); + + /** + * Function to get the distance along the surface + */ + double get_distance_along_surface(); + + private: + /** + * the distance from the surface of the plane + */ + double distance_from_surface; + /** + * the distance along the surface of the plane + */ + double distance_along_surface; + }; + } +} + +#endif \ No newline at end of file diff --git a/include/world_builder/world.h b/include/world_builder/world.h index 55fe076f6..5c2d9a69e 100644 --- a/include/world_builder/world.h +++ b/include/world_builder/world.h @@ -22,6 +22,8 @@ #include "world_builder/grains.h" #include "world_builder/parameters.h" +#include "world_builder/utilities.h" +#include "world_builder/objects/distance_from_surface.h" #include @@ -30,6 +32,7 @@ */ namespace WorldBuilder { + namespace Features { class Interface; @@ -188,6 +191,17 @@ namespace WorldBuilder const double depth, const unsigned int composition_number, size_t number_of_grains) const; + /** + * Returns a PlaneDistances object that has the distance from and along a feature plane, + * caculated from the coordinates and the depth of the point. + \param point the coordinates in the cartesian geometry + \param depth the depth of the point + \param name the name of the feature (i.e. the string provided to the key word "name" in the wb file) + */ + Objects::PlaneDistances + distance_to_plane(const std::array &point, + const double depth, + const std::string name) const; /** * The MPI rank. Set to zero if MPI is not available. diff --git a/source/world_builder/features/interface.cc b/source/world_builder/features/interface.cc index e39920eee..f58c8724c 100644 --- a/source/world_builder/features/interface.cc +++ b/source/world_builder/features/interface.cc @@ -176,6 +176,14 @@ namespace WorldBuilder return get_factory_map().at(lower_case_name)->create(world); } + Objects::PlaneDistances + Interface::distance_to_feature_plane(const Point<3> &, + const Objects::NaturalCoordinate &, + const double) const + { + WBAssertThrow(false, "The distance_to_feature_plane is not yet implemented for the desinated object"); + } + } // namespace Features } // namespace WorldBuilder diff --git a/source/world_builder/features/subducting_plate.cc b/source/world_builder/features/subducting_plate.cc index d4f226f98..b60aeeb5a 100644 --- a/source/world_builder/features/subducting_plate.cc +++ b/source/world_builder/features/subducting_plate.cc @@ -671,6 +671,40 @@ namespace WorldBuilder } + Objects::PlaneDistances + SubductingPlate::distance_to_feature_plane(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth) const + { + // The depth variable is the distance from the surface to the position, the depth + // coordinate is the distance from the bottom of the model to the position and + // the starting radius is the distance from the bottom of the model to the surface. + const double starting_radius = position_in_natural_coordinates.get_depth_coordinate() + depth - starting_depth; + + WBAssert(std::abs(starting_radius) > std::numeric_limits::epsilon(), "World Builder error: starting_radius can not be zero. " + << "Position = " << position_in_cartesian_coordinates[0] << ':' << position_in_cartesian_coordinates[1] << ':' << position_in_cartesian_coordinates[2] + << ", natural_coordinate.get_depth_coordinate() = " << position_in_natural_coordinates.get_depth_coordinate() + << ", depth = " << depth + << ", starting_depth " << starting_depth + ); + + WorldBuilder::Utilities::PointDistanceFromCurvedPlanes distance_from_planes = + WorldBuilder::Utilities::distance_point_from_curved_planes(position_in_cartesian_coordinates, + position_in_natural_coordinates, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + this->world->parameters.coordinate_system, + false, + this->x_spline, + this->y_spline); + + Objects::PlaneDistances plane_distances(distance_from_planes.distance_from_plane, distance_from_planes.distance_along_plane); + return plane_distances; + } + /** * Register plugin */ diff --git a/source/world_builder/objects/distance_from_surface.cc b/source/world_builder/objects/distance_from_surface.cc new file mode 100644 index 000000000..35179951b --- /dev/null +++ b/source/world_builder/objects/distance_from_surface.cc @@ -0,0 +1,36 @@ +/* + Copyright (C) 2018 - 2022 by the authors of the World Builder code. + + This file is part of the World Builder. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "world_builder/objects/distance_from_surface.h" + +namespace WorldBuilder +{ + namespace Objects + { + double PlaneDistances::get_distance_from_surface() + { + return this->distance_from_surface; + } + + double PlaneDistances::get_distance_along_surface() + { + return this->distance_along_surface; + } + } +} \ No newline at end of file diff --git a/source/world_builder/world.cc b/source/world_builder/world.cc index a1ed067a7..2ba49c09f 100644 --- a/source/world_builder/world.cc +++ b/source/world_builder/world.cc @@ -29,9 +29,11 @@ #include "world_builder/types/plugin_system.h" #include "world_builder/types/point.h" #include "world_builder/gravity_model/interface.h" +#include "world_builder/features/subducting_plate.h" #include #include +#include #ifdef WB_WITH_MPI #define OMPI_SKIP_MPICXX 1 @@ -413,5 +415,35 @@ namespace WorldBuilder return random_number_engine; } + Objects::PlaneDistances + World::distance_to_plane(const std::array &point_, + const double depth, + const std::string name) const + { + // We receive the cartesian points from the user. + Point<3> point(point_,cartesian); + + WBAssert(!this->limit_debug_consistency_checks || this->parameters.coordinate_system->natural_coordinate_system() == cartesian + || approx(depth, this->parameters.coordinate_system->max_model_depth()-sqrt(point_[0]*point_[0]+point_[1]*point_[1]+point_[2]*point_[2])), + "Inconsistent input. Please check whether the radius in the sperhical coordiantes is consistent with the radius of the planet as defined " + << "in the program that uses the Geodynamic World Builder. " + << "Depth = " << depth << ", radius = " << this->parameters.coordinate_system->max_model_depth() + << ", point = " << point_[0] << " " << point_[1] << " " << point_[2] + << ", radius-point.norm() = " << this->parameters.coordinate_system->max_model_depth()-sqrt(point_[0]*point_[0]+point_[1]*point_[1]+point_[2]*point_[2])); + + Objects::NaturalCoordinate natural_coordinate = Objects::NaturalCoordinate(point,*(this->parameters.coordinate_system)); + + Objects::PlaneDistances plane_distances(0.0, 0.0); + for (auto &&it : this->parameters.features) + { + if (it->get_name() == name) + { + plane_distances = it->distance_to_feature_plane(point, natural_coordinate, depth); + break; + } + } + return plane_distances; + } + } // namespace WorldBuilder diff --git a/tests/unit_tests/approval_tests/approved/unit_test_world_builder.WorldBuilder_Features__Distance_to_Feature_Plane.txt b/tests/unit_tests/approval_tests/approved/unit_test_world_builder.WorldBuilder_Features__Distance_to_Feature_Plane.txt new file mode 100644 index 000000000..073251d23 --- /dev/null +++ b/tests/unit_tests/approval_tests/approved/unit_test_world_builder.WorldBuilder_Features__Distance_to_Feature_Plane.txt @@ -0,0 +1,10 @@ +Test + + +[0] = 7141.78 +[1] = 70.7107 +[2] = 618.443 +[3] = 13.5623 +[4] = inf +[5] = inf + diff --git a/tests/unit_tests/unit_test_world_builder.cc b/tests/unit_tests/unit_test_world_builder.cc index 7a4f90621..8e3cf3c21 100644 --- a/tests/unit_tests/unit_test_world_builder.cc +++ b/tests/unit_tests/unit_test_world_builder.cc @@ -1041,6 +1041,60 @@ TEST_CASE("WorldBuilder Features: Interface") } +TEST_CASE("WorldBuilder Features: Distance to Feature Plane") +{ + std::vector approval_tests; + + // call the distance_to_plane to a subducting plate feature, + std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/subducting_plate_constant_angles_cartesian.wb"; + WorldBuilder::World world1(file_name); + { + std::unique_ptr subducting_plate = Features::Interface::create("Subducting Plate", &world1); + + world1.parameters.enter_subsection("features"); + world1.parameters.enter_subsection("2"); + subducting_plate->parse_entries(world1.parameters); + world1.parameters.leave_subsection(); + world1.parameters.leave_subsection(); + const std::array point1 = {250e3,495e3,800e3}; + const double depth1 = 5.1e3; + auto plane_distances1 = world1.distance_to_plane(point1, depth1, "First subducting plate"); + approval_tests.emplace_back(plane_distances1.get_distance_from_surface()); + approval_tests.emplace_back(plane_distances1.get_distance_along_surface()); + const std::array point2 = {502e3,500e3,800e3}; + const double depth2 = 0.45e3; + auto plane_distances2 = world1.distance_to_plane(point2, depth2, "First subducting plate"); + approval_tests.emplace_back(plane_distances2.get_distance_from_surface()); + approval_tests.emplace_back(plane_distances2.get_distance_along_surface()); + const std::array point3 = {502e3,500e3,800e3}; // point 3, shallower than point2, thus distance from plane = inf + const double depth3 = 0.43e3; + auto plane_distances3 = world1.distance_to_plane(point3, depth3, "First subducting plate"); + approval_tests.emplace_back(plane_distances3.get_distance_from_surface()); + approval_tests.emplace_back(plane_distances3.get_distance_along_surface()); + + ApprovalTests::Approvals::verifyAll("Test", approval_tests); + } + + // call the distance_to_plane to a fault feature, as this is not implemented yet, we should be + // informed by the assertion error message. + std::string file_name2 = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/fault_constant_angles_cartesian.wb"; + WorldBuilder::World world2(file_name2); + { + std::unique_ptr fault = Features::Interface::create("Fault", &world2); + + world2.parameters.enter_subsection("features"); + world2.parameters.enter_subsection("2"); + fault->parse_entries(world2.parameters); + world2.parameters.leave_subsection(); + world2.parameters.leave_subsection(); + const std::array point = {50e3,230e3,800e3}; + const double depth = 10e3; + CHECK_THROWS_WITH(world2.distance_to_plane(point, depth, "First fault"), + Contains("The distance_to_feature_plane is not yet implemented for the desinated object")); + } +} + + TEST_CASE("WorldBuilder Features: Continental Plate") { std::vector approval_tests;