diff --git a/include/world_builder/parameters.h b/include/world_builder/parameters.h index f7adeb6d6..25571778b 100644 --- a/include/world_builder/parameters.h +++ b/include/world_builder/parameters.h @@ -59,6 +59,11 @@ namespace WorldBuilder class Interface; } // namespace GravityModel + namespace Topography + { + class Interface; + } // namespace GravityModel + class World; /** @@ -275,6 +280,14 @@ namespace WorldBuilder */ std::unique_ptr gravity_model; + /** + * A pointers to the topography model. This variable is responsible for + * the topography model and has ownership over it. Therefore a unique + * pointer are used. + * @see CoordinateSystem + */ + std::unique_ptr topography_model; + /** * This function return the current path as stored in the path variable * as a string in json pointer format. diff --git a/include/world_builder/topography/interface.h b/include/world_builder/topography/interface.h new file mode 100644 index 000000000..0581938c7 --- /dev/null +++ b/include/world_builder/topography/interface.h @@ -0,0 +1,157 @@ +/* + Copyright (C) 2018-2025 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_TOPOGRAPHY_INTERFACE_H +#define WORLD_BUILDER_TOPOGRAPHY_INTERFACE_H + +#include "world_builder/topography/interface.h" + +#include "world_builder/parameters.h" +#include "world_builder/types/string.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + class World; + + namespace Topography + { + + class ObjectFactory; + + /** + * This class is an interface for the topography. + */ + class Interface + { + public: + /** + * Destructor + */ + virtual + ~Interface() = default; + + /** + * declare and read in the world builder file into the topography class + */ + static + void declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the topography class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + /** + * A function to register a new type. This is part of the automatic + * registration of the object factory. + */ + static void registerType(const std::string &name, + void ( * /*declare_entries*/)(Parameters &, const std::string &), + ObjectFactory *factory); + + /** + * A function to create a new type. This is part of the automatic + * registration of the object factory. + */ + static std::unique_ptr create(const std::string &name, WorldBuilder::World *world); + + enum SurfaceType + { + reference_surface, + deformed_surface + }; + + SurfaceType surface_type; + + /** + * declare and read in the world builder file into the parameters class + */ + virtual + SurfaceType + get_surface_type() = 0; + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + virtual + double get_topography(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth) const = 0; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + + + private: + static std::map &get_factory_map() + { + static std::map factories; + return factories; + } + + static std::map &get_declare_map() + { + static std::map declares; + return declares; + } + }; + + + + /** + * A class to create new objects + */ + class ObjectFactory + { + public: + virtual std::unique_ptr create(World *world) = 0; + }; + + /** + * A macro which should be in every derived cpp file to automatically + * register it. Because this is a library, we need some extra measures + * to ensure that the static variable is actually initialized. + */ +#define WB_REGISTER_TOPOGRAPHY(klass,name) \ + class klass##Factory : public ObjectFactory { \ + public: \ + klass##Factory() \ + { \ + Interface::registerType(#name, klass::declare_entries, this); \ + } \ + std::unique_ptr create(World *world) override final { \ + return std::unique_ptr(new klass(world)); \ + } \ + }; \ + static klass##Factory global_##klass##Factory; + + } // namespace Topography +} // namespace WorldBuilder + +#endif diff --git a/include/world_builder/topography/uniform.h b/include/world_builder/topography/uniform.h new file mode 100644 index 000000000..bfb618f02 --- /dev/null +++ b/include/world_builder/topography/uniform.h @@ -0,0 +1,87 @@ +/* + Copyright (C) 2018-2025 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_TOPOGRAPHY_MINIMUM_DEPTH_H +#define WORLD_BUILDER_TOPOGRAPHY_MINIMUM_DEPTH_H + +#include "world_builder/topography/interface.h" + +#include "world_builder/utilities.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + + namespace Topography + { + /** + * This implements a minimum depth topography. The minimum depth topography + * finds the minimum depth of a feature and uses that for the topography. + */ + class Uniform final : public Interface + { + public: + /** + * Constructor + */ + Uniform(WorldBuilder::World *world); + + /** + * Destructor + */ + ~ Uniform() override final; + + /** + * declare and read in the world builder file into the topography class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the topography class + */ + void parse_entries(Parameters &prm) override final; + + /** + * declare and read in the world builder file into the topography class + */ + SurfaceType + get_surface_type() override final; + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_topography(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth) const override final; + + private: + + /** + * Whether to consider a reference or deformed surface. + */ + SurfaceType surface_type; + + }; + } // namespace Topography +} // namespace WorldBuilder + +#endif diff --git a/source/world_builder/parameters.cc b/source/world_builder/parameters.cc index 5e1b9d382..b24e66f0d 100644 --- a/source/world_builder/parameters.cc +++ b/source/world_builder/parameters.cc @@ -38,6 +38,7 @@ #include "world_builder/features/subducting_plate.h" #include "world_builder/features/subducting_plate_models/velocity/interface.h" #include "world_builder/gravity_model/interface.h" +#include "world_builder/topography/interface.h" #include "world_builder/types/object.h" #include "world_builder/utilities.h" @@ -2089,7 +2090,11 @@ namespace WorldBuilder */ template std::unique_ptr Parameters::get_unique_pointer(const std::string &name); - + /** + * Returns a vector of pointers to the Topography Model based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template std::unique_ptr Parameters::get_unique_pointer(const std::string &name); /** * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. diff --git a/source/world_builder/topography/interface.cc b/source/world_builder/topography/interface.cc new file mode 100644 index 000000000..bcb5fe569 --- /dev/null +++ b/source/world_builder/topography/interface.cc @@ -0,0 +1,92 @@ +/* + Copyright (C) 2018-2024 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/topography/interface.h" + +#include "world_builder/types/object.h" + +#include + +namespace WorldBuilder +{ + namespace Topography + { + void + Interface::declare_entries(Parameters &prm, const std::string &parent_name, const std::vector &required_entries) + { + + unsigned int counter = 0; + for (auto &it : get_declare_map()) + { + prm.enter_subsection("oneOf"); + { + prm.enter_subsection(std::to_string(counter)); + { + prm.enter_subsection("properties"); + { + prm.declare_entry("", Types::Object(required_entries), "topography"); + + prm.declare_entry("model",Types::String("",it.first), + "The name of the model for topography to use."); + + it.second(prm, parent_name); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + counter++; + + } + } + + void + Interface::registerType(const std::string &name, + void ( *declare_entries)(Parameters &, const std::string &), + ObjectFactory *factory) + { + get_factory_map()[name] = factory; + get_declare_map()[name] = declare_entries; + } + + std::unique_ptr + Interface::create(const std::string &name, WorldBuilder::World *world) + { + std::string lower_case_name; + std::transform(name.begin(), + name.end(), + std::back_inserter(lower_case_name), + ::tolower);; + + // Have a nice assert message to check whether a plugin exists in the case + // of a debug compilation. + WBAssertThrow(get_factory_map().find(lower_case_name) != get_factory_map().end(), + "Internal error: Plugin with name '" << lower_case_name << "' is not found. " + "The size of factories is " << get_factory_map().size() << "."); + + // Using at() because the [] will just insert values + // which is undesirable in this case. An exception is + // thrown when the name is not present. + return get_factory_map().at(lower_case_name)->create(world); + } + } // namespace Topography +} // namespace WorldBuilder + diff --git a/source/world_builder/topography/uniform.cc b/source/world_builder/topography/uniform.cc new file mode 100644 index 000000000..db47f4846 --- /dev/null +++ b/source/world_builder/topography/uniform.cc @@ -0,0 +1,76 @@ +/* + Copyright (C) 2018-2025 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/topography/uniform.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + namespace Topography + { + Uniform::Uniform(WorldBuilder::World *world_) + : + surface_type(reference_surface) + { + this->world = world_; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &/*prm*/, const std::string & /*unused*/) + { + // Nothing to declare. + } + + void + Uniform::parse_entries(Parameters &/*prm*/) + { + // Nothing to parse as surface type is set in header. + } + + /** + * Returns a topography based on the position. In the uniform model, + * we assume there is no topography. + */ + double + Uniform::get_topography(const Point<3> &/*position*/, + const Objects::NaturalCoordinate &/*position_in_natural_coordinates*/, + const double /*depth*/) const + { + return 0; + } + + Uniform::SurfaceType + Uniform::get_surface_type() + { + return surface_type; + } + + /** + * Register plugin + */ + WB_REGISTER_TOPOGRAPHY(Uniform, uniform) + } // namespace Topography +} // namespace WorldBuilder + diff --git a/source/world_builder/world.cc b/source/world_builder/world.cc index 5bfd422f4..5005e4850 100644 --- a/source/world_builder/world.cc +++ b/source/world_builder/world.cc @@ -23,6 +23,7 @@ #include "world_builder/config.h" #include "world_builder/features/subducting_plate.h" #include "world_builder/gravity_model/interface.h" +#include "world_builder/topography/interface.h" #include "world_builder/nan.h" #include "world_builder/point.h" #include "world_builder/types/array.h" @@ -143,6 +144,8 @@ namespace WorldBuilder prm.declare_entry("gravity model", Types::PluginSystem("uniform", GravityModel::Interface::declare_entries, {"model"}, false),"A gravity model for the world."); + prm.declare_entry("topography", Types::PluginSystem("uniform", Topography::Interface::declare_entries, {"model"}, false),"A topography model for the world."); + prm.declare_entry("features", Types::PluginSystem("",Features::Interface::declare_entries, {"model"}),"A list of features."); prm.declare_entry("random number seed", Types::Int(-1), @@ -194,6 +197,17 @@ namespace WorldBuilder } prm.leave_subsection(); + /** + * Fourth load the topography parameters. + */ + prm.topography_model = prm.get_unique_pointer("topography"); + + prm.enter_subsection("topography"); + { + prm.topography_model->parse_entries(prm); + } + prm.leave_subsection(); + prm.get_unique_pointers("features",prm.features); const bool set_cross_section = prm.check_entry("cross section"); @@ -532,8 +546,6 @@ namespace WorldBuilder return properties(point, depth, {{{2,composition_number,0}}})[0]; } - - WorldBuilder::grains World::grains(const std::array &point, const double depth,